Skip to content

Commit

Permalink
Make FFmpeg log level configurable (#2439)
Browse files Browse the repository at this point in the history
Summary:
Undesired logs are one of the loudest UX complains we get.
Yet, loading media files involves uncertainty which is
difficult to debug without debug log.

This commit introduces utility functions to configure logging level
so that we can ask users to enable it when they encounter an issue,
while defaulting to non-verbose option.

Pull Request resolved: #2439

Reviewed By: hwangjeff, xiaohui-zhang

Differential Revision: D36903763

Pulled By: mthrok

fbshipit-source-id: f4ddd9915b13197c2a2eb97e965005b8b5b8d987
  • Loading branch information
mthrok authored and facebook-github-bot committed Jun 4, 2022
1 parent 3229fc5 commit 877a88c
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 22 deletions.
8 changes: 8 additions & 0 deletions docs/source/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ This affects functionalities in :ref:`Sox IO backend<sox_io_backend>` and :ref:`

.. automodule:: torchaudio.utils.sox_utils
:members:

torchaudio.utils.ffmpeg_utils
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Utility module to configure FFmpeg libraries.

.. automodule:: torchaudio.utils.ffmpeg_utils
:members:
17 changes: 2 additions & 15 deletions test/torchaudio_unittest/common_utils/case_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import unittest

import torch
import torchaudio
from torch.testing._internal.common_utils import TestCase as PytorchTestCase
from torchaudio._internal.module_utils import (
is_kaldi_available,
Expand Down Expand Up @@ -112,22 +113,8 @@ class TorchaudioTestCase(TestBaseMixin, PytorchTestCase):
pass


_IS_FFMPEG_AVAILABLE = None


def is_ffmpeg_available():
if _eval_env("TORCHAUDIO_TEST_IN_FBCODE", default=False):
return True

global _IS_FFMPEG_AVAILABLE
if _IS_FFMPEG_AVAILABLE is None:
try:
from torchaudio.io import StreamReader # noqa: F401

_IS_FFMPEG_AVAILABLE = True
except Exception:
_IS_FFMPEG_AVAILABLE = False
return _IS_FFMPEG_AVAILABLE
return torchaudio._extension._FFMPEG_INITIALIZED


_IS_CTC_DECODER_AVAILABLE = None
Expand Down
22 changes: 22 additions & 0 deletions test/torchaudio_unittest/utils/ffmpeg_utils_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from torchaudio.utils import ffmpeg_utils
from torchaudio_unittest.common_utils import PytorchTestCase, skipIfNoFFmpeg


@skipIfNoFFmpeg
class TestFFmpegUtils(PytorchTestCase):
"""Smoke test for ffmpeg_utils module"""

def tearDown(self):
ffmpeg_utils.set_log_level(8)
super().tearDown()

def test_get_log_level(self):
"""`get_log_level` does not exhibit abnormal behavior"""
for _ in range(10):
ffmpeg_utils.get_log_level()

def test_set_log_level(self):
"""`set_log_level` persists log level"""
for i in range(-100, 100):
ffmpeg_utils.set_log_level(i)
assert ffmpeg_utils.get_log_level() == i
11 changes: 6 additions & 5 deletions torchaudio/csrc/ffmpeg/stream_reader_binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ c10::intrusive_ptr<StreamReaderBinding> init(
using S = const c10::intrusive_ptr<StreamReaderBinding>&;

TORCH_LIBRARY_FRAGMENT(torchaudio, m) {
m.def("torchaudio::ffmpeg_init", []() {
avdevice_register_all();
if (av_log_get_level() == AV_LOG_INFO) {
av_log_set_level(AV_LOG_ERROR);
}
m.def("torchaudio::ffmpeg_init", []() { avdevice_register_all(); });
m.def("torchaudio::ffmpeg_get_log_level", []() -> int64_t {
return static_cast<int64_t>(av_log_get_level());
});
m.def("torchaudio::ffmpeg_set_log_level", [](int64_t level) {
av_log_set_level(static_cast<int>(level));
});
m.class_<StreamReaderBinding>("ffmpeg_StreamReader")
.def(torch::init<>(init))
Expand Down
4 changes: 2 additions & 2 deletions torchaudio/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from torchaudio._internal import module_utils as _mod_utils

from . import sox_utils
from . import ffmpeg_utils, sox_utils
from .download import download_asset

if _mod_utils.is_sox_available():
sox_utils.set_verbosity(0)


__all__ = [
"download_asset",
"sox_utils",
"ffmpeg_utils",
]
45 changes: 45 additions & 0 deletions torchaudio/utils/ffmpeg_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import torch


def get_log_level() -> int:
"""Get the log level of FFmpeg.
See :py:func:`set_log_level` for the detailo.
"""
return torch.ops.torchaudio.ffmpeg_get_log_level()


def set_log_level(level: int):
"""Set the log level of FFmpeg (libavformat etc)
Arguments:
level (int): Log level. The larger, the more verbose.
The following values are common values, the corresponding ``ffmpeg``'s
``-loglevel`` option value and desription.
* ``-8`` (``quiet``):
Print no output.
* ``0`` (``panic``):
Something went really wrong and we will crash now.
* ``8`` (``fatal``):
Something went wrong and recovery is not possible.
For example, no header was found for a format which depends
on headers or an illegal combination of parameters is used.
* ``16`` (``error``):
Something went wrong and cannot losslessly be recovered.
However, not all future data is affected.
* ``24`` (``warning``):
Something somehow does not look correct.
This may or may not lead to problems.
* ``32`` (``info``):
Standard information.
* ``40`` (``verbose``):
Detailed information.
* ``48`` (``debug``):
Stuff which is only useful for libav* developers.
* ``56`` (``trace``):
Extremely verbose debugging, useful for libav* development.
"""
torch.ops.torchaudio.ffmpeg_set_log_level(level)

0 comments on commit 877a88c

Please sign in to comment.