Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "libav_deps.h" // MUST BE INCLUDED FIRST
19 : #include "media_decoder.h"
20 : #include "media_device.h"
21 : #include "media_buffer.h"
22 : #include "media_io_handle.h"
23 : #include "audio/ringbufferpool.h"
24 : #include "decoder_finder.h"
25 : #include "manager.h"
26 :
27 : #ifdef ENABLE_HWACCEL
28 : #include "video/accel.h"
29 : #endif
30 :
31 : #include "string_utils.h"
32 : #include "logger.h"
33 : #include "client/jami_signal.h"
34 :
35 : #include <unistd.h>
36 : #include <cstddef>
37 : #include <thread> // hardware_concurrency
38 : #include <chrono>
39 : #include <algorithm>
40 : #include <asio/steady_timer.hpp>
41 :
42 : namespace jami {
43 :
44 : // maximum number of packets the jitter buffer can queue
45 : const unsigned jitterBufferMaxSize_ {1500};
46 : // maximum time a packet can be queued
47 : const constexpr auto jitterBufferMaxDelay_ = std::chrono::milliseconds(50);
48 :
49 483 : MediaDemuxer::MediaDemuxer()
50 483 : : inputCtx_(avformat_alloc_context())
51 966 : , startTime_(AV_NOPTS_VALUE)
52 483 : {}
53 :
54 483 : MediaDemuxer::~MediaDemuxer()
55 : {
56 483 : if (streamInfoTimer_) {
57 0 : streamInfoTimer_->cancel();
58 0 : streamInfoTimer_.reset();
59 : }
60 483 : if (inputCtx_)
61 411 : avformat_close_input(&inputCtx_);
62 483 : av_dict_free(&options_);
63 483 : }
64 :
65 : const char*
66 0 : MediaDemuxer::getStatusStr(Status status)
67 : {
68 0 : switch (status) {
69 0 : case Status::Success:
70 0 : return "Success";
71 0 : case Status::EndOfFile:
72 0 : return "End of file";
73 0 : case Status::ReadBufferOverflow:
74 0 : return "Read overflow";
75 0 : case Status::ReadError:
76 0 : return "Read error";
77 0 : case Status::FallBack:
78 0 : return "Fallback";
79 0 : case Status::RestartRequired:
80 0 : return "Restart required";
81 0 : default:
82 0 : return "Undefined";
83 : }
84 : }
85 :
86 : int
87 492 : MediaDemuxer::openInput(const DeviceParams& params)
88 : {
89 492 : inputParams_ = params;
90 492 : const auto* iformat = av_find_input_format(params.format.c_str());
91 :
92 492 : if (!iformat && !params.format.empty())
93 1 : JAMI_WARNING("Unable to find format \"{}\"", params.format);
94 :
95 : // A failed avformat_open_input frees the context, but capture may retry.
96 492 : if (!inputCtx_) {
97 10 : inputCtx_ = avformat_alloc_context();
98 10 : if (!inputCtx_) {
99 0 : JAMI_ERROR("Unable to allocate input format context");
100 0 : return AVERROR(ENOMEM);
101 : }
102 : }
103 492 : inputCtx_->interrupt_callback = interruptCallback_;
104 :
105 492 : if (iformat && iformat == av_find_input_format("video4linux2")) {
106 : // Both V4L2 aliases resolve to this format. O_NONBLOCK keeps VIDIOC_DQBUF
107 : // from blocking capture shutdown; decode() already handles EAGAIN.
108 15 : inputCtx_->flags |= AVFMT_FLAG_NONBLOCK;
109 : }
110 :
111 492 : std::string input;
112 :
113 492 : if (params.input == "pipewiregrab") {
114 : //
115 : // We rely on pipewiregrab for screen/window sharing on Wayland.
116 : // Because pipewiregrab is a "video source filter" (part of FFmpeg's libavfilter
117 : // library), its options must all be passed as part of the `input` string.
118 : //
119 4 : input = fmt::format("pipewiregrab=draw_mouse=1:fd={}:node={}", params.fd, params.node);
120 2 : const auto* filter = avfilter_get_by_name("pipewiregrab");
121 2 : const AVClass* filterClass = filter ? filter->priv_class : nullptr;
122 : // Preview and software screen-share encoding need CPU-readable buffers.
123 2 : if (filterClass && av_opt_find(&filterClass, "enable_dmabuf", nullptr, 0, AV_OPT_SEARCH_FAKE_OBJ))
124 1 : input += ":enable_dmabuf=0";
125 2 : JAMI_LOG("Attempting to open input {}", input);
126 : //
127 : // In all other cases, we use the `options_` AVDictionary to pass options to FFmpeg.
128 : //
129 : // NOTE: We rely on the "lavfi" virtual input device to read pipewiregrab's output
130 : // and create a corresponding stream (cf. the getDeviceParams function in
131 : // daemon/src/media/video/v4l2/video_device_impl.cpp). The `options_` dictionary
132 : // could be used to set lavfi's parameters if that was ever needed, but it isn't at
133 : // the moment. (Doc: https://ffmpeg.org/ffmpeg-devices.html#lavfi)
134 : //
135 : } else {
136 490 : if (params.width and params.height) {
137 0 : auto sizeStr = fmt::format("{}x{}", params.width, params.height);
138 0 : av_dict_set(&options_, "video_size", sizeStr.c_str(), 0);
139 0 : }
140 :
141 490 : if (params.framerate) {
142 : #ifdef _WIN32
143 : // On Windows, framerate settings don't reduce to avrational values
144 : // that correspond to valid video device formats.
145 : // e.g. A the rational<double>(10000000, 333333) or 30.000030000
146 : // will be reduced by av_reduce to 999991/33333 or 30.00003000003
147 : // which cause the device opening routine to fail.
148 : // So we treat this imprecise reduction and adjust the value,
149 : // or let dshow choose the framerate, which is, unfortunately,
150 : // NOT the highest according to our experimentations.
151 : auto framerate {params.framerate.real()};
152 : framerate = params.framerate.numerator() / (params.framerate.denominator() + 0.5);
153 : if (params.framerate.denominator() != 4999998)
154 : av_dict_set(&options_, "framerate", jami::to_string(framerate).c_str(), 0);
155 : #else
156 7 : av_dict_set(&options_, "framerate", jami::to_string(params.framerate.real()).c_str(), 0);
157 : #endif
158 : }
159 :
160 490 : if (params.offset_x || params.offset_y) {
161 0 : av_dict_set(&options_, "offset_x", std::to_string(params.offset_x).c_str(), 0);
162 0 : av_dict_set(&options_, "offset_y", std::to_string(params.offset_y).c_str(), 0);
163 : }
164 490 : if (params.channel)
165 0 : av_dict_set(&options_, "channel", std::to_string(params.channel).c_str(), 0);
166 490 : av_dict_set(&options_, "loop", params.loop.c_str(), 0);
167 490 : av_dict_set(&options_, "sdp_flags", params.sdp_flags.c_str(), 0);
168 :
169 : // Set jitter buffer options
170 490 : av_dict_set(&options_, "reorder_queue_size", std::to_string(jitterBufferMaxSize_).c_str(), 0);
171 490 : auto us = std::chrono::duration_cast<std::chrono::microseconds>(jitterBufferMaxDelay_).count();
172 490 : av_dict_set(&options_, "max_delay", std::to_string(us).c_str(), 0);
173 :
174 490 : if (!params.pixel_format.empty()) {
175 0 : av_dict_set(&options_, "pixel_format", params.pixel_format.c_str(), 0);
176 : }
177 490 : if (!params.window_id.empty()) {
178 0 : av_dict_set(&options_, "window_id", params.window_id.c_str(), 0);
179 : }
180 490 : av_dict_set(&options_, "draw_mouse", "1", 0);
181 490 : av_dict_set(&options_, "is_area", std::to_string(params.is_area).c_str(), 0);
182 :
183 490 : input = params.input;
184 :
185 490 : JAMI_LOG("Attempting to open input {} with format {}, pixel format {}, size {}x{}, rate {}",
186 : input,
187 : params.format,
188 : params.pixel_format,
189 : params.width,
190 : params.height,
191 : params.framerate.real());
192 : }
193 :
194 : // Ask FFmpeg to open the input using the options set above
195 492 : if (params.disable_dts_probe_delay && params.format == "sdp") {
196 171 : av_opt_set_int(inputCtx_, "max_ts_probe", 0, AV_OPT_SEARCH_CHILDREN);
197 171 : av_opt_set_int(inputCtx_, "fpsprobesize", 0, AV_OPT_SEARCH_CHILDREN);
198 : } else {
199 : // Don't waste time fetching framerate when finding stream info
200 321 : av_opt_set_int(inputCtx_, "fpsprobesize", 1, AV_OPT_SEARCH_CHILDREN);
201 : }
202 :
203 492 : int ret = avformat_open_input(&inputCtx_, input.c_str(), iformat, options_ ? &options_ : NULL);
204 :
205 492 : if (ret) {
206 82 : JAMI_ERROR("avformat_open_input failed: {}", libav_utils::getError(ret));
207 410 : } else if (inputCtx_->nb_streams > 0 && inputCtx_->streams[0]->codecpar) {
208 402 : baseWidth_ = inputCtx_->streams[0]->codecpar->width;
209 402 : baseHeight_ = inputCtx_->streams[0]->codecpar->height;
210 402 : JAMI_LOG("Opened input using format {:s} and resolution {:d}x{:d}", params.format, baseWidth_, baseHeight_);
211 : }
212 :
213 492 : return ret;
214 492 : }
215 :
216 : int64_t
217 10 : MediaDemuxer::getDuration() const
218 : {
219 10 : return inputCtx_->duration;
220 : }
221 :
222 : bool
223 6 : MediaDemuxer::seekFrame(int, int64_t timestamp)
224 : {
225 6 : std::lock_guard lk(inputCtxMutex_);
226 6 : if (av_seek_frame(inputCtx_, -1, timestamp, AVSEEK_FLAG_BACKWARD) >= 0) {
227 6 : clearFrames();
228 6 : return true;
229 : }
230 0 : return false;
231 6 : }
232 :
233 : void
234 402 : MediaDemuxer::findStreamInfo(bool videoStream)
235 : {
236 402 : if (not streamInfoFound_) {
237 402 : inputCtx_->max_analyze_duration = 30l * AV_TIME_BASE;
238 402 : if (videoStream && keyFrameRequestCb_) {
239 169 : if (!streamInfoTimer_)
240 169 : streamInfoTimer_ = std::make_unique<asio::steady_timer>(*Manager::instance().ioContext());
241 169 : streamInfoTimer_->expires_after(std::chrono::milliseconds(1500));
242 169 : streamInfoTimer_->async_wait([weak = weak_from_this()](const std::error_code& ec) {
243 169 : if (ec)
244 76 : return;
245 93 : if (auto self = weak.lock()) {
246 93 : if (!self->streamInfoFound_) {
247 93 : JAMI_LOG("findStreamInfo: 1500ms elapsed, requesting keyframe to aid probing");
248 93 : if (self->keyFrameRequestCb_)
249 93 : self->keyFrameRequestCb_();
250 : }
251 93 : }
252 : });
253 : }
254 :
255 402 : int err = avformat_find_stream_info(inputCtx_, nullptr);
256 402 : if (err < 0) {
257 0 : JAMI_ERROR("Unable to find stream info: {}", libav_utils::getError(err));
258 : }
259 402 : streamInfoFound_ = true;
260 402 : if (streamInfoTimer_) {
261 169 : streamInfoTimer_->cancel();
262 169 : streamInfoTimer_.reset();
263 : }
264 : }
265 402 : }
266 :
267 : int
268 413 : MediaDemuxer::selectStream(AVMediaType type)
269 : {
270 413 : auto sti = av_find_best_stream(inputCtx_, type, -1, -1, nullptr, 0);
271 413 : if (type == AVMEDIA_TYPE_VIDEO && sti >= 0) {
272 180 : auto* st = inputCtx_->streams[sti];
273 180 : auto disposition = st->disposition;
274 180 : if (disposition & AV_DISPOSITION_ATTACHED_PIC) {
275 1 : JAMI_LOG("Skipping attached picture stream");
276 1 : sti = -1;
277 : }
278 : }
279 413 : return sti;
280 : }
281 :
282 : void
283 412 : MediaDemuxer::setInterruptCallback(int (*cb)(void*), void* opaque)
284 : {
285 412 : interruptCallback_ = {cb, opaque};
286 412 : if (inputCtx_)
287 411 : inputCtx_->interrupt_callback = interruptCallback_;
288 412 : }
289 : void
290 11 : MediaDemuxer::setNeedFrameCb(std::function<void()> cb)
291 : {
292 11 : needFrameCb_ = std::move(cb);
293 11 : }
294 :
295 : void
296 11 : MediaDemuxer::setFileFinishedCb(std::function<void(bool)> cb)
297 : {
298 11 : fileFinishedCb_ = std::move(cb);
299 11 : }
300 :
301 : void
302 169 : MediaDemuxer::setKeyFrameRequestCb(std::function<void()> cb)
303 : {
304 169 : keyFrameRequestCb_ = std::move(cb);
305 169 : }
306 :
307 : void
308 6 : MediaDemuxer::clearFrames()
309 : {
310 : {
311 6 : std::lock_guard lk {videoBufferMutex_};
312 6 : while (!videoBuffer_.empty()) {
313 0 : videoBuffer_.pop();
314 : }
315 6 : }
316 : {
317 6 : std::lock_guard lk {audioBufferMutex_};
318 6 : while (!audioBuffer_.empty()) {
319 0 : audioBuffer_.pop();
320 : }
321 6 : }
322 6 : }
323 :
324 : bool
325 0 : MediaDemuxer::emitFrame(bool isAudio)
326 : {
327 0 : if (isAudio) {
328 0 : return pushFrameFrom(audioBuffer_, isAudio, audioBufferMutex_);
329 : } else {
330 0 : return pushFrameFrom(videoBuffer_, isAudio, videoBufferMutex_);
331 : }
332 : }
333 :
334 : bool
335 0 : MediaDemuxer::pushFrameFrom(std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>>& buffer,
336 : bool isAudio,
337 : std::mutex& mutex)
338 : {
339 0 : std::unique_lock lock(mutex);
340 0 : if (buffer.empty()) {
341 0 : if (currentState_ == MediaDemuxer::CurrentState::Finished) {
342 0 : fileFinishedCb_(isAudio);
343 : } else {
344 0 : needFrameCb_();
345 : }
346 0 : return false;
347 : }
348 0 : auto packet = std::move(buffer.front());
349 0 : if (!packet) {
350 0 : return false;
351 : }
352 0 : auto streamIndex = packet->stream_index;
353 0 : if (static_cast<unsigned>(streamIndex) >= streams_.size() || streamIndex < 0) {
354 0 : return false;
355 : }
356 0 : if (auto& cb = streams_[streamIndex]) {
357 0 : buffer.pop();
358 0 : lock.unlock();
359 0 : cb(*packet.get());
360 : }
361 0 : return true;
362 0 : }
363 :
364 : MediaDemuxer::Status
365 91043086 : MediaDemuxer::demuxe()
366 : {
367 0 : auto packet = std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>(av_packet_alloc(), [](AVPacket* p) {
368 91043086 : if (p)
369 91043086 : av_packet_free(&p);
370 91043086 : });
371 :
372 : bool isVideo;
373 : {
374 91043086 : std::lock_guard lk(inputCtxMutex_);
375 91043086 : int ret = av_read_frame(inputCtx_, packet.get());
376 91043086 : if (ret == AVERROR(EAGAIN)) {
377 0 : return Status::Success;
378 91043086 : } else if (ret == AVERROR_EOF) {
379 91042331 : return Status::EndOfFile;
380 755 : } else if (ret < 0) {
381 0 : JAMI_ERROR("Unable to read frame: {}", libav_utils::getError(ret));
382 0 : return Status::ReadError;
383 : }
384 :
385 755 : auto streamIndex = packet->stream_index;
386 755 : if (static_cast<unsigned>(streamIndex) >= streams_.size() || streamIndex < 0) {
387 0 : return Status::Success;
388 : }
389 :
390 755 : isVideo = inputCtx_->streams[streamIndex]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
391 91043086 : }
392 :
393 755 : if (isVideo) {
394 250 : std::lock_guard lk {videoBufferMutex_};
395 250 : videoBuffer_.push(std::move(packet));
396 250 : if (videoBuffer_.size() >= 90) {
397 0 : return Status::ReadBufferOverflow;
398 : }
399 250 : } else {
400 505 : std::lock_guard lk {audioBufferMutex_};
401 505 : audioBuffer_.push(std::move(packet));
402 505 : if (audioBuffer_.size() >= 300) {
403 0 : return Status::ReadBufferOverflow;
404 : }
405 505 : }
406 755 : return Status::Success;
407 91043086 : }
408 :
409 : void
410 780 : MediaDemuxer::setIOContext(MediaIOHandle* ioctx)
411 : {
412 780 : inputCtx_->pb = ioctx->getContext();
413 780 : }
414 :
415 : MediaDemuxer::Status
416 9091 : MediaDemuxer::decode()
417 : {
418 9091 : libjami::PacketBuffer packet(av_packet_alloc());
419 9091 : int ret = av_read_frame(inputCtx_, packet.get());
420 9091 : if (ret == AVERROR(EAGAIN)) {
421 48 : if ((inputParams_.format == "video4linux2" || inputParams_.format == "v4l2")
422 48 : && (inputCtx_->flags & AVFMT_FLAG_NONBLOCK)) {
423 : // A stalled camera must yield even after its last frame deadline.
424 : // Keep polling waits short so capture shutdown can join promptly.
425 24 : int64_t delay = 10000;
426 24 : if (inputParams_.framerate.numerator() > 0) {
427 20 : rational<double> frameTime = 1e6 / inputParams_.framerate;
428 20 : delay = std::clamp<int64_t>(frameTime.real<int64_t>(), 1000, 10000);
429 : }
430 24 : std::this_thread::sleep_for(std::chrono::microseconds(delay));
431 24 : return Status::Success;
432 : }
433 : /*no data available. Calculate time until next frame.
434 : We do not use the emulated frame mechanism from the decoder because it will affect all
435 : platforms. With the current implementation, the demuxer will be waiting just in case when
436 : av_read_frame returns EAGAIN. For some platforms, av_read_frame is blocking and it will
437 : never happen.
438 : */
439 10 : if (inputParams_.framerate.numerator() == 0)
440 5 : return Status::Success;
441 5 : rational<double> frameTime = 1e6 / inputParams_.framerate;
442 5 : int64_t timeToSleep = lastReadPacketTime_ - av_gettime_relative() + frameTime.real<int64_t>();
443 5 : if (timeToSleep <= 0) {
444 4 : return Status::Success;
445 : }
446 1 : std::this_thread::sleep_for(std::chrono::microseconds(timeToSleep));
447 1 : return Status::Success;
448 9057 : } else if (ret == AVERROR_EOF) {
449 165 : return Status::EndOfFile;
450 8892 : } else if (ret == AVERROR(EACCES)) {
451 0 : return Status::RestartRequired;
452 8892 : } else if (ret < 0) {
453 0 : auto media = inputCtx_->streams[0]->codecpar->codec_type;
454 0 : const auto* const type = media == AVMediaType::AVMEDIA_TYPE_AUDIO
455 0 : ? "AUDIO"
456 0 : : (media == AVMediaType::AVMEDIA_TYPE_VIDEO ? "VIDEO" : "UNSUPPORTED");
457 0 : JAMI_ERROR("Unable to read [{}] frame: {}", type, libav_utils::getError(ret));
458 0 : return Status::ReadError;
459 : }
460 :
461 17784 : if ((inputParams_.format == "x11grab" || inputParams_.format == "dxgigrab") && inputCtx_->nb_streams > 0
462 17784 : && inputCtx_->streams[0] && inputCtx_->streams[0]->codecpar) {
463 0 : auto* codecpar = inputCtx_->streams[0]->codecpar;
464 0 : if (baseHeight_ != codecpar->height || baseWidth_ != codecpar->width) {
465 0 : baseHeight_ = codecpar->height;
466 0 : baseWidth_ = codecpar->width;
467 0 : inputParams_.height = ((baseHeight_ >> 3) << 3);
468 0 : inputParams_.width = ((baseWidth_ >> 3) << 3);
469 0 : return Status::RestartRequired;
470 : }
471 : }
472 :
473 8892 : auto streamIndex = packet->stream_index;
474 8892 : if (static_cast<unsigned>(streamIndex) >= streams_.size() || streamIndex < 0) {
475 0 : return Status::Success;
476 : }
477 :
478 8892 : lastReadPacketTime_ = av_gettime_relative();
479 :
480 8892 : auto& cb = streams_[streamIndex];
481 8892 : if (cb) {
482 8887 : DecodeStatus ret = cb(*packet.get());
483 8887 : if (ret == DecodeStatus::FallBack)
484 0 : return Status::FallBack;
485 : }
486 8892 : return Status::Success;
487 9091 : }
488 :
489 0 : MediaDecoder::MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index)
490 0 : : demuxer_(demuxer)
491 0 : , avStream_(demuxer->getStream(index))
492 : {
493 0 : demuxer->setStreamCallback(index, [this](AVPacket& packet) { return decode(packet); });
494 0 : setupStream();
495 0 : }
496 :
497 20 : MediaDecoder::MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index, MediaObserver observer)
498 20 : : demuxer_(demuxer)
499 20 : , avStream_(demuxer->getStream(index))
500 40 : , callback_(std::move(observer))
501 : {
502 20 : demuxer->setStreamCallback(index, [this](AVPacket& packet) { return decode(packet); });
503 20 : setupStream();
504 20 : }
505 :
506 : bool
507 0 : MediaDecoder::emitFrame(bool isAudio)
508 : {
509 0 : return demuxer_->emitFrame(isAudio);
510 : }
511 :
512 10 : MediaDecoder::MediaDecoder()
513 10 : : demuxer_(new MediaDemuxer)
514 10 : {}
515 :
516 452 : MediaDecoder::MediaDecoder(MediaObserver o)
517 452 : : demuxer_(new MediaDemuxer)
518 452 : , callback_(std::move(o))
519 452 : {}
520 :
521 482 : MediaDecoder::~MediaDecoder()
522 : {
523 : #ifdef ENABLE_HWACCEL
524 482 : if (decoderCtx_ && decoderCtx_->hw_device_ctx)
525 0 : av_buffer_unref(&decoderCtx_->hw_device_ctx);
526 : #endif
527 482 : if (decoderCtx_)
528 411 : avcodec_free_context(&decoderCtx_);
529 482 : }
530 :
531 : void
532 12 : MediaDecoder::flushBuffers()
533 : {
534 12 : avcodec_flush_buffers(decoderCtx_);
535 12 : }
536 :
537 : int
538 471 : MediaDecoder::openInput(const DeviceParams& p)
539 : {
540 471 : passthrough_ = p.passthrough;
541 471 : return demuxer_->openInput(p);
542 : }
543 :
544 : void
545 412 : MediaDecoder::setInterruptCallback(int (*cb)(void*), void* opaque)
546 : {
547 412 : demuxer_->setInterruptCallback(cb, opaque);
548 412 : }
549 :
550 : void
551 780 : MediaDecoder::setIOContext(MediaIOHandle* ioctx)
552 : {
553 780 : demuxer_->setIOContext(ioctx);
554 780 : }
555 :
556 : void
557 169 : MediaDecoder::setKeyFrameRequestCb(std::function<void()> cb)
558 : {
559 169 : demuxer_->setKeyFrameRequestCb(std::move(cb));
560 169 : }
561 :
562 : int
563 391 : MediaDecoder::setup(AVMediaType type)
564 : {
565 391 : demuxer_->findStreamInfo(type == AVMEDIA_TYPE_VIDEO);
566 391 : auto stream = demuxer_->selectStream(type);
567 391 : if (stream < 0) {
568 0 : JAMI_ERROR("No stream found for type {}", static_cast<int>(type));
569 0 : return -1;
570 : }
571 391 : avStream_ = demuxer_->getStream(stream);
572 391 : if (avStream_ == nullptr) {
573 0 : JAMI_ERROR("No stream found at index {}", stream);
574 0 : return -1;
575 : }
576 9278 : demuxer_->setStreamCallback(stream, [this](AVPacket& packet) { return decode(packet); });
577 391 : return setupStream();
578 : }
579 :
580 : int
581 411 : MediaDecoder::setupStream()
582 : {
583 411 : int ret = 0;
584 411 : decoderReady_ = false;
585 411 : avcodec_free_context(&decoderCtx_);
586 :
587 411 : if (prepareDecoderContext() < 0)
588 0 : return -1; // failed
589 :
590 : #ifdef ENABLE_HWACCEL
591 : // if there was a fallback to software decoding, do not enable accel
592 : // it has been disabled already by the video_receive_thread/video_input
593 411 : enableAccel_ &= Manager::instance().videoPreferences.getDecodingAccelerated();
594 :
595 411 : if (enableAccel_ and not fallback_) {
596 411 : auto APIs = video::HardwareAccel::getCompatibleAccel(decoderCtx_->codec_id,
597 411 : decoderCtx_->width,
598 411 : decoderCtx_->height,
599 411 : CODEC_DECODER);
600 759 : for (const auto& it : APIs) {
601 348 : accel_ = std::make_unique<video::HardwareAccel>(it); // save accel
602 348 : auto ret = accel_->initAPI(false, nullptr);
603 348 : if (ret < 0) {
604 348 : accel_.reset();
605 348 : continue;
606 : }
607 0 : if (prepareDecoderContext() < 0)
608 0 : return -1; // failed
609 0 : accel_->setDetails(decoderCtx_);
610 0 : decoderCtx_->opaque = accel_.get();
611 0 : decoderCtx_->pix_fmt = accel_->getFormat();
612 0 : if (avcodec_open2(decoderCtx_, inputDecoder_, &options_) < 0) {
613 : // Failed to open codec
614 0 : JAMI_WARNING("Fail to open hardware decoder for {} with {}",
615 : avcodec_get_name(decoderCtx_->codec_id),
616 : it.getName());
617 0 : avcodec_free_context(&decoderCtx_);
618 0 : decoderCtx_ = nullptr;
619 0 : accel_.reset();
620 0 : continue;
621 : } else {
622 : // Codec opened successfully.
623 0 : JAMI_WARNING("Using hardware decoding for {} with {}",
624 : avcodec_get_name(decoderCtx_->codec_id),
625 : it.getName());
626 0 : break;
627 : }
628 : }
629 411 : }
630 : #endif
631 :
632 411 : JAMI_LOG("Using {} ({}) decoder for {}",
633 : inputDecoder_->long_name,
634 : inputDecoder_->name,
635 : av_get_media_type_string(avStream_->codecpar->codec_type));
636 411 : decoderCtx_->thread_count = std::max(1, std::min(8, static_cast<int>(std::thread::hardware_concurrency()) / 2));
637 411 : if (emulateRate_)
638 0 : JAMI_LOG("Using framerate emulation");
639 411 : startTime_ = av_gettime(); // Used to set pts after decoding, and for rate emulation
640 :
641 : #ifdef ENABLE_HWACCEL
642 411 : if (!accel_) {
643 411 : JAMI_WARNING("Not using hardware decoding for {}", avcodec_get_name(decoderCtx_->codec_id));
644 411 : ret = avcodec_open2(decoderCtx_, inputDecoder_, nullptr);
645 : }
646 : #else
647 : ret = avcodec_open2(decoderCtx_, inputDecoder_, nullptr);
648 : #endif
649 411 : if (ret < 0) {
650 0 : JAMI_ERROR("Unable to open codec: {}", libav_utils::getError(ret));
651 0 : return -1;
652 : }
653 :
654 411 : decoderReady_ = true;
655 411 : return 0;
656 : }
657 :
658 : int
659 411 : MediaDecoder::prepareDecoderContext()
660 : {
661 411 : inputDecoder_ = findDecoder(avStream_->codecpar->codec_id);
662 411 : if (!inputDecoder_) {
663 0 : JAMI_ERROR("Unsupported codec");
664 0 : return -1;
665 : }
666 :
667 411 : decoderCtx_ = avcodec_alloc_context3(inputDecoder_);
668 411 : if (!decoderCtx_) {
669 0 : JAMI_ERROR("Failed to create decoder context");
670 0 : return -1;
671 : }
672 411 : avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar);
673 411 : decoderCtx_->pkt_timebase = avStream_->time_base;
674 411 : width_ = decoderCtx_->width;
675 411 : height_ = decoderCtx_->height;
676 411 : decoderCtx_->framerate = avStream_->avg_frame_rate;
677 411 : if (avStream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
678 179 : if (decoderCtx_->framerate.num == 0 || decoderCtx_->framerate.den == 0)
679 169 : decoderCtx_->framerate = inputParams_.framerate;
680 179 : if (decoderCtx_->framerate.num == 0 || decoderCtx_->framerate.den == 0)
681 169 : decoderCtx_->framerate = {30, 1};
682 232 : } else if (avStream_->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
683 232 : if (decoderCtx_->codec_id == AV_CODEC_ID_OPUS) {
684 230 : av_opt_set_int(decoderCtx_, "decode_fec", fecEnabled_ ? 1 : 0, AV_OPT_SEARCH_CHILDREN);
685 : }
686 232 : auto format = libav_utils::choose_sample_fmt_default(
687 232 : inputDecoder_, Manager::instance().getRingBufferPool().getInternalAudioFormat().sampleFormat);
688 232 : decoderCtx_->sample_fmt = format;
689 232 : decoderCtx_->request_sample_fmt = format;
690 : }
691 411 : return 0;
692 : }
693 :
694 : void
695 54 : MediaDecoder::updateStartTime(int64_t startTime)
696 : {
697 54 : startTime_ = startTime;
698 54 : }
699 :
700 : DecodeStatus
701 8887 : MediaDecoder::decode(AVPacket& packet)
702 : {
703 8887 : if (inputDecoder_->type == AVMEDIA_TYPE_VIDEO && passthrough_) {
704 : #ifdef ENABLE_VIDEO
705 : // If passthrough, we don't decode, just pass the packet
706 0 : auto f = std::static_pointer_cast<MediaFrame>(std::make_shared<VideoFrame>());
707 0 : if (auto p = av_packet_clone(&packet)) {
708 0 : f->setPacket(libjami::PacketBuffer(p));
709 : }
710 0 : if (callback_)
711 0 : callback_(std::move(f));
712 :
713 0 : if (contextCallback_ && firstDecode_.load()) {
714 0 : firstDecode_.exchange(false);
715 0 : contextCallback_();
716 : }
717 0 : return DecodeStatus::FrameFinished;
718 : #endif
719 0 : }
720 :
721 8887 : int frameFinished = 0;
722 8887 : auto ret = avcodec_send_packet(decoderCtx_, &packet);
723 : // TODO: Investigate avcodec_send_packet returning AVERROR_INVALIDDATA.
724 : // * Bug Windows documented here: git.jami.net/savoirfairelinux/jami-daemon/-/issues/1116
725 : // where avcodec_send_packet returns AVERROR_INVALIDDATA when the size information in the
726 : // packet is incorrect. Falling back onto sw decoding in this causes a segfault.
727 : // * A second problem occurs on some Windows devices with intel CPUs in which hardware
728 : // decoding fails with AVERROR_INVALIDDATA when using H.264. However, in this scenario,
729 : // falling back to software decoding works fine.
730 : // We need to figure out why this behavior occurs and how to discriminate between the two.
731 8887 : if (ret < 0 && ret != AVERROR(EAGAIN)) {
732 : #ifdef ENABLE_HWACCEL
733 0 : if (accel_) {
734 0 : JAMI_WARNING("Decoding error falling back to software");
735 0 : fallback_ = true;
736 0 : accel_.reset();
737 0 : avcodec_flush_buffers(decoderCtx_);
738 0 : setupStream();
739 0 : return DecodeStatus::FallBack;
740 : }
741 : #endif
742 0 : avcodec_flush_buffers(decoderCtx_);
743 0 : return ret == AVERROR_EOF ? DecodeStatus::Success : DecodeStatus::DecodeError;
744 : }
745 :
746 : #ifdef ENABLE_VIDEO
747 8887 : auto f = (inputDecoder_->type == AVMEDIA_TYPE_VIDEO)
748 17742 : ? std::static_pointer_cast<MediaFrame>(std::make_shared<VideoFrame>())
749 17758 : : std::static_pointer_cast<MediaFrame>(std::make_shared<AudioFrame>());
750 : #else
751 : auto f = std::static_pointer_cast<MediaFrame>(std::make_shared<AudioFrame>());
752 : #endif
753 8887 : auto* frame = f->pointer();
754 8887 : ret = avcodec_receive_frame(decoderCtx_, frame);
755 : // time_base is not set in AVCodecContext for decoding
756 : // fail to set it causes pts to be incorrectly computed down in the function
757 8887 : if (inputDecoder_->type == AVMEDIA_TYPE_VIDEO) {
758 8871 : decoderCtx_->time_base.num = decoderCtx_->framerate.den;
759 8871 : decoderCtx_->time_base.den = decoderCtx_->framerate.num;
760 : } else {
761 16 : decoderCtx_->time_base.num = 1;
762 16 : decoderCtx_->time_base.den = decoderCtx_->sample_rate;
763 : }
764 8887 : frame->time_base = decoderCtx_->time_base;
765 8887 : if (resolutionChangedCallback_) {
766 8871 : if (decoderCtx_->width != width_ or decoderCtx_->height != height_) {
767 0 : JAMI_LOG("Resolution changed from {}x{} to {}x{}", width_, height_, decoderCtx_->width, decoderCtx_->height);
768 0 : width_ = decoderCtx_->width;
769 0 : height_ = decoderCtx_->height;
770 0 : resolutionChangedCallback_(width_, height_);
771 : }
772 : }
773 8887 : if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
774 0 : return DecodeStatus::DecodeError;
775 : }
776 8887 : if (ret >= 0)
777 8573 : frameFinished = 1;
778 :
779 8887 : if (frameFinished) {
780 8573 : if (inputDecoder_->type == AVMEDIA_TYPE_VIDEO) {
781 8557 : frame->format = (AVPixelFormat) correctPixFmt(frame->format);
782 : } else {
783 : // It's possible (albeit rare) for avcodec_receive_frame to return a frame with
784 : // unspecified channel order. This can cause issues later on in the resampler
785 : // because swr_convert_frame expects the ch_layout of the input frame to match
786 : // the in_ch_layout of the SwrContext, but swr_init sets in_ch_layout to a default
787 : // value based on the number of channels if the channel order of the input frame
788 : // is unspecified.
789 16 : if (frame->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
790 16 : av_channel_layout_default(&frame->ch_layout, frame->ch_layout.nb_channels);
791 : }
792 : }
793 8573 : auto packetTimestamp = frame->pts; // in stream time base
794 8573 : frame->pts = av_rescale_q_rnd(av_gettime() - startTime_,
795 : {1, AV_TIME_BASE},
796 8573 : decoderCtx_->time_base,
797 : static_cast<AVRounding>(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
798 8573 : lastTimestamp_ = frame->pts;
799 8573 : if (emulateRate_ and packetTimestamp != AV_NOPTS_VALUE) {
800 0 : auto startTime = avStream_->start_time == AV_NOPTS_VALUE ? 0 : avStream_->start_time;
801 0 : rational<double> frame_time = rational<double>(getTimeBase())
802 0 : * rational<double>(static_cast<double>(packetTimestamp - startTime));
803 0 : auto target_relative = static_cast<std::int64_t>(frame_time.real() * 1e6);
804 0 : auto target_absolute = startTime_ + target_relative;
805 0 : if (target_relative < seekTime_) {
806 0 : return DecodeStatus::Success;
807 : }
808 : // required frame found. Reset seek time
809 0 : if (target_relative >= seekTime_) {
810 0 : resetSeekTime();
811 : }
812 0 : auto now = av_gettime();
813 0 : if (target_absolute > now) {
814 0 : std::this_thread::sleep_for(std::chrono::microseconds(target_absolute - now));
815 : }
816 : }
817 :
818 8573 : if (callback_)
819 8573 : callback_(std::move(f));
820 :
821 8573 : if (contextCallback_ && firstDecode_.load()) {
822 39 : firstDecode_.exchange(false);
823 39 : contextCallback_();
824 : }
825 8573 : return DecodeStatus::FrameFinished;
826 : }
827 314 : return DecodeStatus::Success;
828 0 : }
829 :
830 : void
831 12 : MediaDecoder::setSeekTime(int64_t time)
832 : {
833 12 : seekTime_ = time;
834 12 : }
835 :
836 : MediaDemuxer::Status
837 9052 : MediaDecoder::decode()
838 : {
839 9052 : auto ret = demuxer_->decode();
840 9052 : if (ret == MediaDemuxer::Status::RestartRequired) {
841 0 : avcodec_flush_buffers(decoderCtx_);
842 0 : setupStream();
843 0 : ret = MediaDemuxer::Status::EndOfFile;
844 : }
845 9052 : return ret;
846 : }
847 :
848 : #ifdef ENABLE_VIDEO
849 : #ifdef ENABLE_HWACCEL
850 : void
851 0 : MediaDecoder::enableAccel(bool enableAccel)
852 : {
853 0 : enableAccel_ = enableAccel;
854 0 : emitSignal<libjami::ConfigurationSignal::HardwareDecodingChanged>(enableAccel_);
855 0 : if (!enableAccel) {
856 0 : accel_.reset();
857 0 : if (decoderCtx_)
858 0 : decoderCtx_->opaque = nullptr;
859 : }
860 0 : }
861 : #endif
862 :
863 : DecodeStatus
864 0 : MediaDecoder::flush()
865 : {
866 0 : int frameFinished = 0;
867 0 : int ret = 0;
868 0 : ret = avcodec_send_packet(decoderCtx_, nullptr);
869 0 : if (ret < 0 && ret != AVERROR(EAGAIN))
870 0 : return ret == AVERROR_EOF ? DecodeStatus::Success : DecodeStatus::DecodeError;
871 :
872 0 : auto result = std::make_shared<MediaFrame>();
873 0 : ret = avcodec_receive_frame(decoderCtx_, result->pointer());
874 0 : if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
875 0 : return DecodeStatus::DecodeError;
876 0 : if (ret >= 0)
877 0 : frameFinished = 1;
878 :
879 0 : if (frameFinished) {
880 0 : if (inputDecoder_->type == AVMEDIA_TYPE_VIDEO)
881 0 : result->pointer()->format = (AVPixelFormat) correctPixFmt(result->pointer()->format);
882 0 : if (callback_)
883 0 : callback_(std::move(result));
884 0 : return DecodeStatus::FrameFinished;
885 : }
886 :
887 0 : return DecodeStatus::Success;
888 0 : }
889 : #endif // ENABLE_VIDEO
890 :
891 : int
892 189 : MediaDecoder::getWidth() const
893 : {
894 189 : return decoderCtx_ ? decoderCtx_->width : 0;
895 : }
896 :
897 : int
898 189 : MediaDecoder::getHeight() const
899 : {
900 189 : return decoderCtx_ ? decoderCtx_->height : 0;
901 : }
902 :
903 : std::string
904 0 : MediaDecoder::getDecoderName() const
905 : {
906 0 : return decoderCtx_ ? decoderCtx_->codec->name : "";
907 : }
908 :
909 : rational<double>
910 10 : MediaDecoder::getFps() const
911 : {
912 10 : return {(double) avStream_->avg_frame_rate.num, (double) avStream_->avg_frame_rate.den};
913 : }
914 :
915 : rational<unsigned>
916 0 : MediaDecoder::getTimeBase() const
917 : {
918 0 : return {(unsigned) avStream_->time_base.num, (unsigned) avStream_->time_base.den};
919 : }
920 :
921 : AVPixelFormat
922 11 : MediaDecoder::getPixelFormat() const
923 : {
924 11 : return isReady() ? decoderCtx_->pix_fmt : AV_PIX_FMT_NONE;
925 : }
926 :
927 : int
928 8557 : MediaDecoder::correctPixFmt(int input_pix_fmt)
929 : {
930 : // https://ffmpeg.org/pipermail/ffmpeg-user/2014-February/020152.html
931 : int pix_fmt;
932 8557 : switch (input_pix_fmt) {
933 0 : case AV_PIX_FMT_YUVJ420P:
934 0 : pix_fmt = AV_PIX_FMT_YUV420P;
935 0 : break;
936 0 : case AV_PIX_FMT_YUVJ422P:
937 0 : pix_fmt = AV_PIX_FMT_YUV422P;
938 0 : break;
939 0 : case AV_PIX_FMT_YUVJ444P:
940 0 : pix_fmt = AV_PIX_FMT_YUV444P;
941 0 : break;
942 0 : case AV_PIX_FMT_YUVJ440P:
943 0 : pix_fmt = AV_PIX_FMT_YUV440P;
944 0 : break;
945 8557 : default:
946 8557 : pix_fmt = input_pix_fmt;
947 8557 : break;
948 : }
949 8557 : return pix_fmt;
950 : }
951 :
952 : MediaStream
953 246 : MediaDecoder::getStream(const std::string& name) const
954 : {
955 246 : if (!decoderCtx_) {
956 47 : JAMI_WARNING("No decoder context");
957 47 : return {};
958 : }
959 199 : auto ms = MediaStream(name, decoderCtx_, lastTimestamp_);
960 : #ifdef ENABLE_HWACCEL
961 : // accel_ is null if not using accelerated codecs
962 199 : if (accel_)
963 67 : ms.format = accel_->getSoftwareFormat();
964 : #endif
965 199 : return ms;
966 199 : }
967 :
968 : } // namespace jami
|