Skip to content

Commit 95fb639

Browse files
committed
Merge branch 'av-sync'
2 parents 2dbe427 + ff9b17a commit 95fb639

File tree

7 files changed

+231
-165
lines changed

7 files changed

+231
-165
lines changed

picamera/camera.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,9 @@ def split_recording(self, output, splitter_port=1, **options):
10861086
and *inline_headers* must be ``True`` when :meth:`start_recording` is
10871087
called (this is the default).
10881088
1089+
The method returns the meta-data of the first :class:`PiVideoFrame`
1090+
that is written to the new output.
1091+
10891092
.. versionchanged:: 1.3
10901093
The *splitter_port* parameter was added
10911094
@@ -1103,7 +1106,7 @@ def split_recording(self, output, splitter_port=1, **options):
11031106
'There is no recording in progress on '
11041107
'port %d' % splitter_port)
11051108
else:
1106-
encoder.split(output, options.get('motion_output'))
1109+
return encoder.split(output, options.get('motion_output'))
11071110

11081111
def request_key_frame(self, splitter_port=1):
11091112
"""

picamera/encoders.py

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ def __init__(
600600
super(PiVideoEncoder, self).__init__(
601601
parent, camera_port, input_port, format, resize, **options)
602602
self._next_output = []
603+
self._split_frame = None
603604
self.frame = None
604605

605606
def _create_encoder(
@@ -844,7 +845,7 @@ def split(self, output, motion_output=None):
844845
# intra_period / framerate gives the time between I-frames (which
845846
# should also coincide with SPS headers). We multiply by three to
846847
# ensure the timeout is deliberately excessive, and clamp the minimum
847-
# timeout to 10 seconds (otherwise unencoded formats tend to fail
848+
# timeout to 15 seconds (otherwise unencoded formats tend to fail
848849
# presumably due to I/O capacity)
849850
if self.parent:
850851
framerate = self.parent.framerate + self.parent.framerate_delta
@@ -856,18 +857,20 @@ def split(self, output, motion_output=None):
856857
if not self.event.wait(timeout):
857858
raise PiCameraRuntimeError('Timed out waiting for a split point')
858859
self.event.clear()
860+
return self._split_frame
859861

860862
def _callback_write(self, buf, key=PiVideoFrameType.frame):
861863
"""
862864
Extended to implement video frame meta-data tracking, and to handle
863865
splitting video recording to the next output when :meth:`split` is
864866
called.
865867
"""
866-
self.frame = PiVideoFrame(
868+
last_frame = self.frame
869+
this_frame = PiVideoFrame(
867870
index=
868-
self.frame.index + 1
869-
if self.frame.complete else
870-
self.frame.index,
871+
last_frame.index + 1
872+
if last_frame.complete else
873+
last_frame.index,
871874
frame_type=
872875
PiVideoFrameType.key_frame
873876
if buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_KEYFRAME else
@@ -878,22 +881,24 @@ def _callback_write(self, buf, key=PiVideoFrameType.frame):
878881
PiVideoFrameType.frame,
879882
frame_size=
880883
buf.length
881-
if self.frame.complete else
882-
self.frame.frame_size + buf.length,
884+
if last_frame.complete else
885+
last_frame.frame_size + buf.length,
883886
video_size=
884-
self.frame.video_size
887+
last_frame.video_size
885888
if buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO else
886-
self.frame.video_size + buf.length,
889+
last_frame.video_size + buf.length,
887890
split_size=
888-
self.frame.split_size
891+
last_frame.split_size
889892
if buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO else
890-
self.frame.split_size + buf.length,
893+
last_frame.split_size + buf.length,
891894
timestamp=
892-
None
895+
# Time cannot go backwards, so if we've got an unknown pts
896+
# simply repeat the last one
897+
last_frame.timestamp
893898
if buf.pts in (0, mmal.MMAL_TIME_UNKNOWN) else
894899
buf.pts,
895900
complete=
896-
bool(buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_FRAME_END),
901+
bool(buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_FRAME_END)
897902
)
898903
if self._intra_period == 1 or (buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_CONFIG):
899904
with self.outputs_lock:
@@ -906,18 +911,20 @@ def _callback_write(self, buf, key=PiVideoFrameType.frame):
906911
self._close_output(new_key)
907912
self._open_output(new_output, new_key)
908913
if new_key == PiVideoFrameType.frame:
909-
self.frame = PiVideoFrame(
910-
index=self.frame.index,
911-
frame_type=self.frame.frame_type,
912-
frame_size=self.frame.frame_size,
913-
video_size=self.frame.video_size,
914+
this_frame = PiVideoFrame(
915+
index=this_frame.index,
916+
frame_type=this_frame.frame_type,
917+
frame_size=this_frame.frame_size,
918+
video_size=this_frame.video_size,
914919
split_size=0,
915-
timestamp=self.frame.timestamp,
916-
complete=self.frame.complete,
920+
timestamp=this_frame.timestamp,
921+
complete=this_frame.complete,
917922
)
923+
self._split_frame = this_frame
918924
self.event.set()
919925
if buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO:
920926
key = PiVideoFrameType.motion_data
927+
self.frame = this_frame
921928
return super(PiVideoEncoder, self)._callback_write(buf, key)
922929

923930

picamera/frames.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,9 @@ class PiVideoFrame(namedtuple('PiVideoFrame', (
150150
.. warning::
151151
152152
Currently, the camera occasionally returns "time unknown" values in
153-
this field which picamera represents as ``None``. If you are
154-
querying this property you will need to check the value is not
155-
``None`` before using it. This happens for SPS header "frames",
156-
for example.
153+
this field. In this case, picamera will simply re-use the timestamp
154+
of the previous frame (under the assumption that time never goes
155+
backwards). This happens for SPS header "frames", for example.
157156
158157
.. attribute:: complete
159158
@@ -213,4 +212,3 @@ def header(self):
213212
'PiVideoFrame.frame_type for equality with '
214213
'PiVideoFrameType.sps_header instead'))
215214
return self.frame_type == PiVideoFrameType.sps_header
216-

0 commit comments

Comments
 (0)