Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions av/container/core.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,52 @@ Flags = define_enum('Flags', __name__, (
), is_flags=True)


AudioCodecs = define_enum('AudioCodecs', __name__, (
('NONE', lib.AV_CODEC_ID_NONE),
('PCM_ALAW', lib.AV_CODEC_ID_PCM_ALAW),
('PCM_BLURAY', lib.AV_CODEC_ID_PCM_BLURAY),
('PCM_DVD', lib.AV_CODEC_ID_PCM_DVD),
('PCM_F16LE', lib.AV_CODEC_ID_PCM_F16LE),
('PCM_F24LE', lib.AV_CODEC_ID_PCM_F24LE),
('PCM_F32BE', lib.AV_CODEC_ID_PCM_F32BE),
('PCM_F32LE', lib.AV_CODEC_ID_PCM_F32LE),
('PCM_F64BE', lib.AV_CODEC_ID_PCM_F64BE),
('PCM_F64LE', lib.AV_CODEC_ID_PCM_F64LE),
('PCM_LXF', lib.AV_CODEC_ID_PCM_LXF),
('PCM_MULAW', lib.AV_CODEC_ID_PCM_MULAW),
('PCM_S16BE', lib.AV_CODEC_ID_PCM_S16BE),
('PCM_S16BE_PLANAR', lib.AV_CODEC_ID_PCM_S16BE_PLANAR),
('PCM_S16LE', lib.AV_CODEC_ID_PCM_S16LE),
('PCM_S16LE_PLANAR', lib.AV_CODEC_ID_PCM_S16LE_PLANAR),
('PCM_S24BE', lib.AV_CODEC_ID_PCM_S24BE),
('PCM_S24DAUD', lib.AV_CODEC_ID_PCM_S24DAUD),
('PCM_S24LE', lib.AV_CODEC_ID_PCM_S24LE),
('PCM_S24LE_PLANAR', lib.AV_CODEC_ID_PCM_S24LE_PLANAR),
('PCM_S32BE', lib.AV_CODEC_ID_PCM_S32BE),
('PCM_S32LE', lib.AV_CODEC_ID_PCM_S32LE),
('PCM_S32LE_PLANAR', lib.AV_CODEC_ID_PCM_S32LE_PLANAR),
('PCM_S64BE', lib.AV_CODEC_ID_PCM_S64BE),
('PCM_S64LE', lib.AV_CODEC_ID_PCM_S64LE),
('PCM_S8', lib.AV_CODEC_ID_PCM_S8),
('PCM_S8_PLANAR', lib.AV_CODEC_ID_PCM_S8_PLANAR),
('PCM_U16BE', lib.AV_CODEC_ID_PCM_U16BE),
('PCM_U16LE', lib.AV_CODEC_ID_PCM_U16LE),
('PCM_U24BE', lib.AV_CODEC_ID_PCM_U24BE),
('PCM_U24LE', lib.AV_CODEC_ID_PCM_U24LE),
('PCM_U32BE', lib.AV_CODEC_ID_PCM_U32BE),
('PCM_U32LE', lib.AV_CODEC_ID_PCM_U32LE),
('PCM_U8', lib.AV_CODEC_ID_PCM_U8),
('PCM_VIDC', lib.AV_CODEC_ID_PCM_VIDC)
))


cdef class Container(object):

def __cinit__(self, sentinel, file_, format_name, options,
container_options, stream_options,
metadata_encoding, metadata_errors,
buffer_size, open_timeout, read_timeout,
io_open):
io_open, audio_codec=None):

if sentinel is not _cinit_sentinel:
raise RuntimeError('cannot construct base Container')
Expand Down Expand Up @@ -240,6 +279,9 @@ cdef class Container(object):
self.ptr.flags |= lib.AVFMT_FLAG_GENPTS
self.ptr.opaque = <void*>self

if audio_codec is not None:
self.ptr.audio_codec_id = AudioCodecs[audio_codec]

# Setup Python IO.
self.open_files = {}
if not isinstance(file_, basestring):
Expand Down Expand Up @@ -338,7 +380,8 @@ cdef class Container(object):
def open(file, mode=None, format=None, options=None,
container_options=None, stream_options=None,
metadata_encoding='utf-8', metadata_errors='strict',
buffer_size=32768, timeout=None, io_open=None):
buffer_size=32768, timeout=None, io_open=None,
audio_codec=None):
"""open(file, mode='r', **kwargs)

Main entrypoint to opening files/streams.
Expand All @@ -365,6 +408,10 @@ def open(file, mode=None, format=None, options=None,
``url`` is the url to open, ``flags`` is a combination of AVIO_FLAG_* and
``options`` is a dictionary of additional options. The callable should return a
file-like object.
:param str audio_codec: Specify audio input codec to be used when reading
form ALSA or PulseAudio devices. For example ``"PCM_S32LE"`` or
``"PCM_S16BE"``. If not given, the codec is left unconfigured and
defaults to FFmpeg default.

For devices (via ``libavdevice``), pass the name of the device to ``format``,
e.g.::
Expand Down Expand Up @@ -397,13 +444,19 @@ def open(file, mode=None, format=None, options=None,
open_timeout = timeout
read_timeout = timeout

if audio_codec is not None:
try:
AudioCodecs[audio_codec]
except KeyError:
raise ValueError("Provided audio_codec must be one of the supported audio codecs")

if mode.startswith('r'):
return InputContainer(
_cinit_sentinel, file, format, options,
container_options, stream_options,
metadata_encoding, metadata_errors,
buffer_size, open_timeout, read_timeout,
io_open
io_open, audio_codec
)
if mode.startswith('w'):
if stream_options:
Expand Down
35 changes: 35 additions & 0 deletions include/libavcodec/avcodec.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,41 @@ cdef extern from "libavcodec/avcodec.h" nogil:
AV_CODEC_ID_NONE
AV_CODEC_ID_MPEG2VIDEO
AV_CODEC_ID_MPEG1VIDEO
# Audio codecs.
AV_CODEC_ID_PCM_ALAW
AV_CODEC_ID_PCM_BLURAY
AV_CODEC_ID_PCM_DVD
AV_CODEC_ID_PCM_F16LE
AV_CODEC_ID_PCM_F24LE
AV_CODEC_ID_PCM_F32BE
AV_CODEC_ID_PCM_F32LE
AV_CODEC_ID_PCM_F64BE
AV_CODEC_ID_PCM_F64LE
AV_CODEC_ID_PCM_LXF
AV_CODEC_ID_PCM_MULAW
AV_CODEC_ID_PCM_S16BE
AV_CODEC_ID_PCM_S16BE_PLANAR
AV_CODEC_ID_PCM_S16LE
AV_CODEC_ID_PCM_S16LE_PLANAR
AV_CODEC_ID_PCM_S24BE
AV_CODEC_ID_PCM_S24DAUD
AV_CODEC_ID_PCM_S24LE
AV_CODEC_ID_PCM_S24LE_PLANAR
AV_CODEC_ID_PCM_S32BE
AV_CODEC_ID_PCM_S32LE
AV_CODEC_ID_PCM_S32LE_PLANAR
AV_CODEC_ID_PCM_S64BE
AV_CODEC_ID_PCM_S64LE
AV_CODEC_ID_PCM_S8
AV_CODEC_ID_PCM_S8_PLANAR
AV_CODEC_ID_PCM_U16BE
AV_CODEC_ID_PCM_U16LE
AV_CODEC_ID_PCM_U24BE
AV_CODEC_ID_PCM_U24LE
AV_CODEC_ID_PCM_U32BE
AV_CODEC_ID_PCM_U32LE
AV_CODEC_ID_PCM_U8
AV_CODEC_ID_PCM_VIDC

cdef enum AVDiscard:
AVDISCARD_NONE
Expand Down
3 changes: 3 additions & 0 deletions include/libavformat/avformat.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ cdef extern from "libavformat/avformat.h" nogil:

AVDictionary *metadata

# Forced audio codec set by user.
AVCodecID audio_codec_id

char filename
int64_t start_time
int64_t duration
Expand Down
8 changes: 8 additions & 0 deletions tests/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,11 @@ def test_buffertoosmall(self):
self.assertEqual(e.errno, av.error.BUFFER_TOO_SMALL.value)
else:
self.fail("no exception raised")

def test_not_supported_audio_codec(self):
try:
av.open("alsa_device", audio_codec="does_not_exist")
except ValueError as e:
self.assertEqual(str(e), "Provided audio_codec must be one of the supported audio codecs")
else:
self.fail("no exception raised")