Skip to content

Commit

Permalink
Build with ffmpeg 7
Browse files Browse the repository at this point in the history
  • Loading branch information
WyattBlue authored Jul 26, 2024
1 parent 5595308 commit b2193fd
Show file tree
Hide file tree
Showing 31 changed files with 207 additions and 450 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ jobs:
matrix:
config:
- {os: ubuntu-latest, python: "3.8", ffmpeg: "6.1", extras: true}
# TODO: - {os: ubuntu-latest, python: "3.8", ffmpeg: "7.0"}
- {os: ubuntu-latest, python: "3.8", ffmpeg: "6.0"}
- {os: ubuntu-latest, python: pypy3.9, ffmpeg: "6.1"}
- {os: macos-12, python: "3.8", ffmpeg: "7.0"}
- {os: macos-12, python: "3.8", ffmpeg: "6.1"}

env:
Expand Down Expand Up @@ -116,6 +118,7 @@ jobs:
fail-fast: false
matrix:
config:
- {os: windows-latest, python: "3.8", ffmpeg: "7.0"}
- {os: windows-latest, python: "3.8", ffmpeg: "6.1"}
- {os: windows-latest, python: "3.8", ffmpeg: "6.0"}

Expand Down
2 changes: 0 additions & 2 deletions av/audio/codeccontext.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ from av.codec.context cimport CodecContext


cdef class AudioCodecContext(CodecContext):

# Hold onto the frames that we will decode until we have a full one.
cdef AudioFrame next_frame

# For encoding.
cdef AudioResampler resampler
4 changes: 2 additions & 2 deletions av/audio/codeccontext.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ class AudioCodecContext(CodecContext):
frame_size: int
sample_rate: int
rate: int
channels: int
channel_layout: int
layout: AudioLayout
format: AudioFormat
type: Literal["audio"]

@property
def channels(self) -> int: ...
def encode(self, frame: AudioFrame | None = None) -> list[Packet]: ...
def encode_lazy(self, frame: AudioFrame | None = None) -> Iterator[Packet]: ...
def decode(self, packet: Packet | None = None) -> list[AudioFrame]: ...
24 changes: 3 additions & 21 deletions av/audio/codeccontext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ cdef class AudioCodecContext(CodecContext):
cdef _init(self, lib.AVCodecContext *ptr, const lib.AVCodec *codec):
CodecContext._init(self, ptr, codec)

# Sometimes there isn't a layout set, but there are a number of
# channels. Assume it is the default layout.
# TODO: Put this behind `not bare_metal`.
# TODO: Do this more efficiently.
if self.ptr.channels and not self.ptr.channel_layout:
self.ptr.channel_layout = get_audio_layout(self.ptr.channels, 0).layout

cdef _set_default_time_base(self):
self.ptr.time_base.num = 1
self.ptr.time_base.den = self.ptr.sample_rate
Expand Down Expand Up @@ -62,7 +55,6 @@ cdef class AudioCodecContext(CodecContext):
"""
return self.ptr.frame_size


@property
def sample_rate(self):
"""
Expand All @@ -85,18 +77,9 @@ cdef class AudioCodecContext(CodecContext):
def rate(self, value):
self.sample_rate = value

# TODO: Integrate into AudioLayout.
@property
def channels(self):
return self.ptr.channels

@channels.setter
def channels(self, value):
self.ptr.channels = value
self.ptr.channel_layout = lib.av_get_default_channel_layout(value)
@property
def channel_layout(self):
return self.ptr.channel_layout
return self.layout.nb_channels

@property
def layout(self):
Expand All @@ -105,13 +88,12 @@ cdef class AudioCodecContext(CodecContext):
:type: AudioLayout
"""
return get_audio_layout(self.ptr.channels, self.ptr.channel_layout)
return get_audio_layout(self.ptr.ch_layout)

@layout.setter
def layout(self, value):
cdef AudioLayout layout = AudioLayout(value)
self.ptr.channel_layout = layout.layout
self.ptr.channels = layout.nb_channels
self.ptr.ch_layout = layout.layout

@property
def format(self):
Expand Down
6 changes: 3 additions & 3 deletions av/audio/fifo.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ cdef class AudioFifo:

self.ptr = lib.av_audio_fifo_alloc(
<lib.AVSampleFormat>frame.ptr.format,
len(frame.layout.channels), # TODO: Can we safely use frame.ptr.nb_channels?
frame.layout.nb_channels,
frame.ptr.nb_samples * 2, # Just a default number of samples; it will adjust.
)

Expand All @@ -71,7 +71,7 @@ cdef class AudioFifo:
# Make sure nothing changed.
elif (
frame.ptr.format != self.template.ptr.format or
frame.ptr.channel_layout != self.template.ptr.channel_layout or
# TODO: frame.ptr.ch_layout != self.template.ptr.ch_layout or
frame.ptr.sample_rate != self.template.ptr.sample_rate or
(frame._time_base.num and self.template._time_base.num and (
frame._time_base.num != self.template._time_base.num or
Expand Down Expand Up @@ -131,7 +131,7 @@ cdef class AudioFifo:
frame._copy_internal_attributes(self.template)
frame._init(
<lib.AVSampleFormat>self.template.ptr.format,
self.template.ptr.channel_layout,
<lib.AVChannelLayout>self.template.ptr.ch_layout,
samples,
1, # Align?
)
Expand Down
3 changes: 1 addition & 2 deletions av/audio/frame.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ from av.frame cimport Frame


cdef class AudioFrame(Frame):

# For raw storage of the frame's data; don't ever touch this.
cdef uint8_t *_buffer
cdef size_t _buffer_size
Expand All @@ -26,7 +25,7 @@ cdef class AudioFrame(Frame):
:type: AudioFormat
"""

cdef _init(self, lib.AVSampleFormat format, uint64_t layout, unsigned int nb_samples, unsigned int align)
cdef _init(self, lib.AVSampleFormat format, lib.AVChannelLayout layout, unsigned int nb_samples, unsigned int align)
cdef _init_user_attributes(self)

cdef AudioFrame alloc_audio_frame()
24 changes: 8 additions & 16 deletions av/audio/frame.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ from av.audio.plane cimport AudioPlane
from av.error cimport err_check
from av.utils cimport check_ndarray, check_ndarray_shape

import warnings

from av.deprecation import AVDeprecationWarning


cdef object _cinit_bypass_sentinel

Expand Down Expand Up @@ -47,26 +43,22 @@ cdef class AudioFrame(Frame):
cdef AudioLayout cy_layout = AudioLayout(layout)
self._init(cy_format.sample_fmt, cy_layout.layout, samples, align)

cdef _init(self, lib.AVSampleFormat format, uint64_t layout, unsigned int nb_samples, unsigned int align):

cdef _init(self, lib.AVSampleFormat format, lib.AVChannelLayout layout, unsigned int nb_samples, unsigned int align):
self.ptr.nb_samples = nb_samples
self.ptr.format = <int>format
self.ptr.channel_layout = layout
self.ptr.ch_layout = layout

# Sometimes this is called twice. Oh well.
self._init_user_attributes()

# Audio filters need AVFrame.channels to match number of channels from layout.
self.ptr.channels = self.layout.nb_channels

if self.layout.channels and nb_samples:
if self.layout.nb_channels != 0 and nb_samples:
# Cleanup the old buffer.
lib.av_freep(&self._buffer)

# Get a new one.
self._buffer_size = err_check(lib.av_samples_get_buffer_size(
NULL,
len(self.layout.channels),
self.layout.nb_channels,
nb_samples,
format,
align
Expand All @@ -78,7 +70,7 @@ cdef class AudioFrame(Frame):
# Connect the data pointers to the buffer.
err_check(lib.avcodec_fill_audio_frame(
self.ptr,
len(self.layout.channels),
self.layout.nb_channels,
<lib.AVSampleFormat>self.ptr.format,
self._buffer,
self._buffer_size,
Expand All @@ -89,7 +81,7 @@ cdef class AudioFrame(Frame):
lib.av_freep(&self._buffer)

cdef _init_user_attributes(self):
self.layout = get_audio_layout(0, self.ptr.channel_layout)
self.layout = get_audio_layout(self.ptr.ch_layout)
self.format = get_audio_format(<lib.AVSampleFormat>self.ptr.format)

def __repr__(self):
Expand All @@ -114,7 +106,7 @@ cdef class AudioFrame(Frame):
)

# check input format
nb_channels = len(AudioLayout(layout).channels)
nb_channels = AudioLayout(layout).nb_channels
check_ndarray(array, dtype, 2)
if AudioFormat(format).is_planar:
check_ndarray_shape(array, array.shape[0] == nb_channels)
Expand Down Expand Up @@ -188,6 +180,6 @@ cdef class AudioFrame(Frame):
if self.format.is_planar:
count = self.samples
else:
count = self.samples * len(self.layout.channels)
count = self.samples * self.layout.nb_channels

return np.vstack([np.frombuffer(x, dtype=dtype, count=count) for x in self.planes])
26 changes: 4 additions & 22 deletions av/audio/layout.pxd
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
from libc.stdint cimport uint64_t
cimport libav as lib


cdef class AudioLayout:
cdef lib.AVChannelLayout layout
cdef _init(self, lib.AVChannelLayout layout)

# The layout for FFMpeg; this is essentially a bitmask of channels.
cdef uint64_t layout
cdef int nb_channels

cdef readonly tuple channels
"""
A tuple of :class:`AudioChannel` objects.
:type: tuple
"""

cdef _init(self, uint64_t layout)


cdef class AudioChannel:

# The channel for FFmpeg.
cdef uint64_t channel


cdef AudioLayout get_audio_layout(int channels, uint64_t c_layout)
cdef AudioLayout get_audio_layout(lib.AVChannelLayout c_layout)
10 changes: 1 addition & 9 deletions av/audio/layout.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
channel_descriptions: dict[str, str]

class AudioLayout:
name: str
layout: int
nb_channels: int
channels: tuple[AudioChannel, ...]
def __init__(self, layout: int | str | AudioLayout): ...

class AudioChannel:
name: str
description: str
def __init__(self, layout: str | AudioLayout): ...
Loading

0 comments on commit b2193fd

Please sign in to comment.