LCOV - code coverage report
Current view: top level - foo/src/media - libav_utils.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 47 66 71.2 %
Date: 2026-04-01 09:29:43 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.14