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