LCOV - code coverage report
Current view: top level - src/media - media_decoder.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 279 479 58.2 %
Date: 2024-04-23 08:02:50 Functions: 44 62 71.0 %

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

Generated by: LCOV version 1.14