diff --git a/docs/source/utils.rst b/docs/source/utils.rst index a755939dd0..708486cf3b 100644 --- a/docs/source/utils.rst +++ b/docs/source/utils.rst @@ -11,3 +11,11 @@ This affects functionalities in :ref:`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: diff --git a/test/torchaudio_unittest/common_utils/case_utils.py b/test/torchaudio_unittest/common_utils/case_utils.py index 828759f2da..29d2efd6a1 100644 --- a/test/torchaudio_unittest/common_utils/case_utils.py +++ b/test/torchaudio_unittest/common_utils/case_utils.py @@ -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, @@ -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 diff --git a/test/torchaudio_unittest/utils/ffmpeg_utils_test.py b/test/torchaudio_unittest/utils/ffmpeg_utils_test.py new file mode 100644 index 0000000000..f902173647 --- /dev/null +++ b/test/torchaudio_unittest/utils/ffmpeg_utils_test.py @@ -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 diff --git a/torchaudio/csrc/ffmpeg/stream_reader_binding.cpp b/torchaudio/csrc/ffmpeg/stream_reader_binding.cpp index 5bf12a37ee..dca6ed784d 100644 --- a/torchaudio/csrc/ffmpeg/stream_reader_binding.cpp +++ b/torchaudio/csrc/ffmpeg/stream_reader_binding.cpp @@ -29,11 +29,12 @@ c10::intrusive_ptr init( using S = const c10::intrusive_ptr&; 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(av_log_get_level()); + }); + m.def("torchaudio::ffmpeg_set_log_level", [](int64_t level) { + av_log_set_level(static_cast(level)); }); m.class_("ffmpeg_StreamReader") .def(torch::init<>(init)) diff --git a/torchaudio/utils/__init__.py b/torchaudio/utils/__init__.py index 90874dd225..6ef13ebbe4 100644 --- a/torchaudio/utils/__init__.py +++ b/torchaudio/utils/__init__.py @@ -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", ] diff --git a/torchaudio/utils/ffmpeg_utils.py b/torchaudio/utils/ffmpeg_utils.py new file mode 100644 index 0000000000..2612ba56fc --- /dev/null +++ b/torchaudio/utils/ffmpeg_utils.py @@ -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)