Skip to content

Commit c2f8ab5

Browse files
committed
Add PyavOutput support for vc4 platforms
Make the PyavOutput work with existing non-libav encoders that don't pass a "packet" - so instead we have to make one up. Signed-off-by: David Plowman <[email protected]>
1 parent 87d7bc5 commit c2f8ab5

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

picamera2/encoders/h264_encoder.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ def _start(self):
8484
self._controls += [(V4L2_CID_MPEG_VIDEO_H264_MIN_QP, self.qp)]
8585
self._controls += [(V4L2_CID_MPEG_VIDEO_H264_MAX_QP, self.qp)]
8686

87+
# The output objects may need to know what kind of stream this is.
88+
for out in self._output:
89+
out._add_stream("video", "h264")
90+
8791
super()._start()
8892

8993
def _setup(self, quality):

picamera2/encoders/mjpeg_encoder.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,10 @@ def _setup(self, quality):
3434
actual_complexity = self.width * self.height * getattr(self, "framerate", 30)
3535
reference_bitrate = BITRATE_TABLE[quality] * 1000000
3636
self.bitrate = int(reference_bitrate * actual_complexity / reference_complexity)
37+
38+
def _start(self):
39+
# The output objects may need to know what kind of stream this is.
40+
for out in self._output:
41+
out._add_stream("video", "mjpeg", rate=30) # seem to need a rate to prevent timestamp warnings
42+
43+
super()._start()

picamera2/outputs/pyavoutput.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from fractions import Fraction
2+
13
import av
24

35
from .output import Output
@@ -50,15 +52,26 @@ def stop(self):
5052
except Exception:
5153
pass
5254
self._container = None
55+
self._streams = {}
5356

5457
def outputframe(self, frame, keyframe=True, timestamp=None, packet=None, audio=False):
5558
"""Output an encoded frame using PyAv."""
5659
if self.recording and self._container:
57-
orig_stream = packet.stream
58-
if orig_stream not in self._streams:
59-
raise RuntimeError("Stream not found in PyavOutput")
60-
# Here we replace in encoder's stream by the corresponding one for our output container.
61-
packet.stream = self._streams[orig_stream]
60+
orig_stream = None
61+
# We must make a packet that looks like it came from our own container's version of the stream.
62+
if not packet:
63+
# No packet present. It must have come from a video encoder that isn't using libav, so make one up.
64+
packet = av.Packet(frame)
65+
packet.dts = timestamp
66+
packet.pts = timestamp
67+
packet.time_base = Fraction(1, 1000000)
68+
packet.stream = self._streams["video"]
69+
else:
70+
# We can perform a switcheroo on the packet's stream, swapping the encoder's version for ours!
71+
orig_stream = packet.stream
72+
if orig_stream not in self._streams:
73+
raise RuntimeError("Stream not found in PyavOutput")
74+
packet.stream = self._streams[orig_stream]
6275

6376
try:
6477
self._container.mux(packet)
@@ -74,4 +87,5 @@ def outputframe(self, frame, keyframe=True, timestamp=None, packet=None, audio=F
7487
# Put the original stream back, just in case the encoder has multiple outputs and will pass
7588
# it to each one.
7689
packet.stream = orig_stream
90+
7791
self.outputtimestamp(timestamp)

0 commit comments

Comments
 (0)