LCOV - code coverage report
Current view: top level - src/media - libav_utils.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 71.2 % 66 47
Test Date: 2026-06-13 09:18:46 Functions: 62.5 % 16 10

            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          182 : choose_sample_fmt(const AVCodec* codec, const AVSampleFormat* preferred_formats, int preferred_formats_count)
      50              : {
      51          182 :     if (codec->sample_fmts)
      52          182 :         for (int i = 0; i < preferred_formats_count; ++i) {
      53          363 :             for (const auto* it = codec->sample_fmts; *it != -1; ++it) {
      54          363 :                 if (*it == preferred_formats[i])
      55          182 :                     return preferred_formats[i];
      56              :             }
      57              :         }
      58            0 :     return AV_SAMPLE_FMT_NONE;
      59              : }
      60              : 
      61              : AVSampleFormat
      62          182 : choose_sample_fmt_default(const AVCodec* codec, AVSampleFormat defaultFormat)
      63              : {
      64              :     // List of supported formats, current default first
      65          182 :     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          182 :                                                 AV_SAMPLE_FMT_S32};
      74          182 :     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           59 : getError(int err)
     235              : {
     236           59 :     std::string ret(AV_ERROR_MAX_STRING_SIZE, '\0');
     237           59 :     av_strerror(err, (char*) ret.data(), ret.size());
     238           59 :     return ret;
     239            0 : }
     240              : 
     241              : const char*
     242           49 : getDictValue(const AVDictionary* d, const std::string& key, int flags)
     243              : {
     244           49 :     auto* kv = av_dict_get(d, key.c_str(), nullptr, flags);
     245           49 :     if (kv)
     246           49 :         return kv->value;
     247              :     else
     248            0 :         return "";
     249              : }
     250              : 
     251              : void
     252          144 : setDictValue(AVDictionary** d, const std::string& key, const std::string& value, int flags)
     253              : {
     254          144 :     av_dict_set(d, key.c_str(), value.c_str(), flags);
     255          144 : }
     256              : 
     257              : void
     258         9233 : fillWithBlack(AVFrame* frame)
     259              : {
     260         9233 :     const AVPixelFormat format = static_cast<AVPixelFormat>(frame->format);
     261         9233 :     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        36932 :     for (int i = 0; i < planes; ++i)
     266        27699 :         linesizes[i] = frame->linesize[i];
     267         9233 :     int ret = av_image_fill_black(frame->data, linesizes, format, frame->color_range, frame->width, frame->height);
     268         9233 :     if (ret < 0) {
     269            0 :         JAMI_ERROR("Failed to blacken frame");
     270              :     }
     271         9233 : }
     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_ERROR("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 2.0-1