LCOV - code coverage report
Current view: top level - src/media - libav_utils.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 44 63 69.8 %
Date: 2024-04-24 08:04:06 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
       5             :  *  Author: Luca Barbato <lu_zero@gentoo.org>
       6             :  *  Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
       7             :  *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
       8             :  *
       9             :  *  This program is free software; you can redistribute it and/or modify
      10             :  *  it under the terms of the GNU General Public License as published by
      11             :  *  the Free Software Foundation; either version 3 of the License, or
      12             :  *  (at your option) any later version.
      13             :  *
      14             :  *  This program is distributed in the hope that it will be useful,
      15             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  *  GNU General Public License for more details.
      18             :  *
      19             :  *  You should have received a copy of the GNU General Public License
      20             :  *  along with this program; if not, write to the Free Software
      21             :  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
      22             :  */
      23             : 
      24             : #include "libav_deps.h" // MUST BE INCLUDED FIRST
      25             : 
      26             : #ifdef HAVE_CONFIG_H
      27             : #include "config.h"
      28             : #endif
      29             : #include "video/video_base.h"
      30             : #include "logger.h"
      31             : 
      32             : #include <vector>
      33             : #include <algorithm>
      34             : #include <string>
      35             : #include <iostream>
      36             : #include <thread>
      37             : #include <mutex>
      38             : #include <exception>
      39             : #include <ciso646> // fix windows compiler bug
      40             : 
      41             : extern "C" {
      42             : #if LIBAVUTIL_VERSION_MAJOR < 56
      43             : AVFrameSideData*
      44             : av_frame_new_side_data_from_buf(AVFrame* frame, enum AVFrameSideDataType type, AVBufferRef* buf)
      45             : {
      46             :     auto side_data = av_frame_new_side_data(frame, type, 0);
      47             :     av_buffer_unref(&side_data->buf);
      48             :     side_data->buf = buf;
      49             :     side_data->data = side_data->buf->data;
      50             :     side_data->size = side_data->buf->size;
      51             :     return side_data;
      52             : }
      53             : #endif
      54             : }
      55             : 
      56             : namespace jami {
      57             : namespace libav_utils {
      58             : 
      59             : AVSampleFormat
      60         196 : choose_sample_fmt(const AVCodec* codec,
      61             :                   const AVSampleFormat* preferred_formats,
      62             :                   int preferred_formats_count)
      63             : {
      64         196 :     if (codec->sample_fmts)
      65         196 :         for (int i = 0; i < preferred_formats_count; ++i) {
      66         391 :             for (auto it = codec->sample_fmts; *it != -1; ++it) {
      67         391 :                 if (*it == preferred_formats[i])
      68         196 :                     return preferred_formats[i];
      69             :             }
      70             :         }
      71           0 :     return AV_SAMPLE_FMT_NONE;
      72             : }
      73             : 
      74             : AVSampleFormat
      75         196 : choose_sample_fmt_default(const AVCodec* codec, AVSampleFormat defaultFormat)
      76             : {
      77             :     // List of supported formats, current default first
      78         196 :     const AVSampleFormat preferred_formats[] = {defaultFormat,
      79             :                                                 AV_SAMPLE_FMT_FLTP,
      80             :                                                 AV_SAMPLE_FMT_FLT,
      81             :                                                 AV_SAMPLE_FMT_S16P,
      82             :                                                 AV_SAMPLE_FMT_S16,
      83             :                                                 AV_SAMPLE_FMT_DBLP,
      84             :                                                 AV_SAMPLE_FMT_DBL,
      85             :                                                 AV_SAMPLE_FMT_S32P,
      86         196 :                                                 AV_SAMPLE_FMT_S32};
      87         196 :     return choose_sample_fmt(codec,
      88             :                              preferred_formats,
      89         196 :                              sizeof(preferred_formats) / sizeof(preferred_formats[0]));
      90             : }
      91             : 
      92             : #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
      93             : // protect libav/ffmpeg access
      94             : static int
      95             : avcodecManageMutex(void** data, enum AVLockOp op)
      96             : {
      97             :     auto mutex = reinterpret_cast<std::mutex**>(data);
      98             :     int ret = 0;
      99             :     switch (op) {
     100             :     case AV_LOCK_CREATE:
     101             :         try {
     102             :             *mutex = new std::mutex;
     103             :         } catch (const std::bad_alloc& e) {
     104             :             return AVERROR(ENOMEM);
     105             :         }
     106             :         break;
     107             :     case AV_LOCK_OBTAIN:
     108             :         (*mutex)->lock();
     109             :         break;
     110             :     case AV_LOCK_RELEASE:
     111             :         (*mutex)->unlock();
     112             :         break;
     113             :     case AV_LOCK_DESTROY:
     114             :         delete *mutex;
     115             :         *mutex = nullptr;
     116             :         break;
     117             :     default:
     118             : #ifdef AVERROR_BUG
     119             :         return AVERROR_BUG;
     120             : #else
     121             :         break;
     122             : #endif
     123             :     }
     124             :     return AVERROR(ret);
     125             : }
     126             : #endif
     127             : 
     128             : static constexpr const char* AVLOGLEVEL = "AVLOGLEVEL";
     129             : 
     130             : static void
     131          38 : setAvLogLevel()
     132             : {
     133          38 :     char* envvar = getenv(AVLOGLEVEL);
     134          38 :     signed level = AV_LOG_WARNING;
     135             : 
     136          38 :     if (envvar != nullptr) {
     137           0 :         level = to_int<int>(envvar, AV_LOG_ERROR);
     138           0 :         level = std::max(AV_LOG_QUIET, std::min(level, AV_LOG_DEBUG));
     139             :     }
     140          38 :     av_log_set_level(level);
     141          38 : }
     142             : 
     143             : #ifdef __ANDROID__
     144             : static void
     145             : androidAvLogCb(void* ptr, int level, const char* fmt, va_list vl)
     146             : {
     147             :     if (level > av_log_get_level())
     148             :         return;
     149             : 
     150             :     char line[1024];
     151             :     int print_prefix = 1;
     152             :     int android_level;
     153             :     va_list vl2;
     154             :     va_copy(vl2, vl);
     155             :     av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
     156             :     va_end(vl2);
     157             : 
     158             :     // replace unprintable characters with '?'
     159             :     int idx = 0;
     160             :     while (line[idx]) {
     161             :         if (line[idx] < 0x08 || (line[idx] > 0x0D && line[idx] < 0x20))
     162             :             line[idx] = '?';
     163             :         ++idx;
     164             :     }
     165             : 
     166             :     switch (level) {
     167             :     case AV_LOG_QUIET:
     168             :         android_level = ANDROID_LOG_SILENT;
     169             :         break;
     170             :     case AV_LOG_PANIC:
     171             :         android_level = ANDROID_LOG_FATAL;
     172             :         break;
     173             :     case AV_LOG_FATAL:
     174             :         android_level = ANDROID_LOG_FATAL;
     175             :         break;
     176             :     case AV_LOG_ERROR:
     177             :         android_level = ANDROID_LOG_ERROR;
     178             :         break;
     179             :     case AV_LOG_WARNING:
     180             :         android_level = ANDROID_LOG_WARN;
     181             :         break;
     182             :     case AV_LOG_INFO:
     183             :         android_level = ANDROID_LOG_INFO;
     184             :         break;
     185             :     case AV_LOG_VERBOSE:
     186             :         android_level = ANDROID_LOG_INFO;
     187             :         break;
     188             :     case AV_LOG_DEBUG:
     189             :         android_level = ANDROID_LOG_DEBUG;
     190             :         break;
     191             :     case AV_LOG_TRACE:
     192             :         android_level = ANDROID_LOG_VERBOSE;
     193             :         break;
     194             :     default:
     195             :         android_level = ANDROID_LOG_DEFAULT;
     196             :         break;
     197             :     }
     198             :     __android_log_print(android_level, "FFmpeg", "%s", line);
     199             : }
     200             : #endif
     201             : 
     202             : static void
     203          38 : init_once()
     204             : {
     205             : #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
     206             :     av_register_all();
     207             : #endif
     208          38 :     avdevice_register_all();
     209          38 :     avformat_network_init();
     210             : #if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(7, 13, 100)
     211             :     avfilter_register_all();
     212             : #endif
     213             : 
     214             : #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
     215             :     av_lockmgr_register(avcodecManageMutex);
     216             : #endif
     217             : 
     218          38 :     setAvLogLevel();
     219             : 
     220             : #ifdef __ANDROID__
     221             :     // android doesn't like stdout and stderr :(
     222             :     av_log_set_callback(androidAvLogCb);
     223             : #endif
     224          38 : }
     225             : 
     226             : static std::once_flag already_called;
     227             : 
     228             : void
     229          45 : av_init()
     230             : {
     231          45 :     std::call_once(already_called, init_once);
     232          45 : }
     233             : 
     234             : bool
     235           0 : is_yuv_planar(const AVPixFmtDescriptor& desc)
     236             : {
     237           0 :     if (not(desc.flags & AV_PIX_FMT_FLAG_PLANAR) or desc.flags & AV_PIX_FMT_FLAG_RGB)
     238           0 :         return false;
     239             : 
     240             :     /* handle formats that do not use all planes */
     241           0 :     unsigned used_bit_mask = (1u << desc.nb_components) - 1;
     242           0 :     for (unsigned i = 0; i < desc.nb_components; ++i)
     243           0 :         used_bit_mask &= ~(1u << desc.comp[i].plane);
     244             : 
     245           0 :     return not used_bit_mask;
     246             : }
     247             : 
     248             : std::string
     249          61 : getError(int err)
     250             : {
     251          61 :     std::string ret(AV_ERROR_MAX_STRING_SIZE, '\0');
     252          61 :     av_strerror(err, (char*) ret.data(), ret.size());
     253          61 :     return ret;
     254           0 : }
     255             : 
     256             : const char*
     257          48 : getDictValue(const AVDictionary* d, const std::string& key, int flags)
     258             : {
     259          48 :     auto kv = av_dict_get(d, key.c_str(), nullptr, flags);
     260          48 :     if (kv)
     261          48 :         return kv->value;
     262             :     else
     263           0 :         return "";
     264             : }
     265             : 
     266             : void
     267         173 : setDictValue(AVDictionary** d, const std::string& key, const std::string& value, int flags)
     268             : {
     269         173 :     av_dict_set(d, key.c_str(), value.c_str(), flags);
     270         173 : }
     271             : 
     272             : void
     273        8966 : fillWithBlack(AVFrame* frame)
     274             : {
     275        8966 :     const AVPixelFormat format = static_cast<AVPixelFormat>(frame->format);
     276        8966 :     const int planes = av_pix_fmt_count_planes(format);
     277             :     // workaround for casting pointers to different sizes
     278             :     // on 64 bit machines: sizeof(ptrdiff_t) != sizeof(int)
     279             :     ptrdiff_t linesizes[4];
     280       35864 :     for (int i = 0; i < planes; ++i)
     281       26898 :         linesizes[i] = frame->linesize[i];
     282        8966 :     int ret = av_image_fill_black(frame->data,
     283             :                                   linesizes,
     284             :                                   format,
     285             :                                   frame->color_range,
     286             :                                   frame->width,
     287             :                                   frame->height);
     288        8966 :     if (ret < 0) {
     289           0 :         JAMI_ERR() << "Failed to blacken frame";
     290             :     }
     291        8966 : }
     292             : 
     293             : void
     294           0 : fillWithSilence(AVFrame* frame)
     295             : {
     296           0 :     int ret = av_samples_set_silence(frame->extended_data,
     297             :                                      0,
     298             :                                      frame->nb_samples,
     299             :                                      frame->ch_layout.nb_channels,
     300           0 :                                      (AVSampleFormat) frame->format);
     301           0 :     if (ret < 0)
     302           0 :         JAMI_ERR() << "Failed to fill frame with silence";
     303           0 : }
     304             : 
     305             : } // namespace libav_utils
     306             : } // namespace jami

Generated by: LCOV version 1.14