LCOV - code coverage report
Current view: top level - src/media - media_decoder.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 63.9 % 543 347
Test Date: 2026-11-09 10:41:14 Functions: 78.4 % 51 40

            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
        

Generated by: LCOV version 2.0-1