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-12-21 08:56:24 Functions: 9 11 81.8 %

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

Generated by: LCOV version 1.14