LCOV - code coverage report
Current view: top level - src/media - media_decoder.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 280 479 58.5 %
Date: 2024-12-21 08:56:24 Functions: 44 62 71.0 %

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

Generated by: LCOV version 1.14