Beispiel #1
0
 def __init__(self,
              camera,
              size=None,
              seconds=None,
              max_frames=None,
              bitrate=17000000,
              splitter_port=1):
     if size is None and seconds is None:
         raise PiCameraValueError(
             'You must specify either size, or seconds')
     if size is not None and seconds is not None:
         raise PiCameraValueError(
             'You cannot specify both size and seconds')
     if seconds is not None:
         size = bitrate * seconds // 8
     super(PiCameraCircularIO, self).__init__(size)
     try:
         camera._encoders
     except AttributeError:
         raise PiCameraValueError('camera must be a valid PiCamera object')
     self.camera = camera
     self.max_frames = max_frames
     self.splitter_port = splitter_port
     self._data = PiCameraDequeHack(self)
     self._frames = PiCameraDequeFrames(self)
Beispiel #2
0
 def __init__(self, camera, size=None, seconds=None, bitrate=17000000):
     if size is None and seconds is None:
         raise PiCameraValueError('You must specify either size, or seconds')
     if size is not None and seconds is not None:
         raise PiCameraValueError('You cannot specify both size and seconds')
     if seconds is not None:
         size = bitrate * seconds // 8
     super(PiCameraCircularIO, self).__init__(size)
     self.camera = camera
     self._data = PiCameraDequeHack(camera)
Beispiel #3
0
 def _set_layer(self, value):
     try:
         if not (0 <= value <= 255):
             raise PiCameraValueError(
                 "Invalid layer value: %d (valid range 0..255)" % value)
     except TypeError:
         raise PiCameraValueError("Invalid layer value: %s" % value)
     mp = mmal.MMAL_DISPLAYREGION_T(mmal.MMAL_PARAMETER_HEADER_T(
         mmal.MMAL_PARAMETER_DISPLAYREGION,
         ct.sizeof(mmal.MMAL_DISPLAYREGION_T)),
                                    set=mmal.MMAL_DISPLAY_SET_LAYER,
                                    layer=value)
     mmal_check(mmal.mmal_port_parameter_set(self.renderer[0].input[0],
                                             mp.hdr),
                prefix="Failed to set layer")
Beispiel #4
0
    def copy_to(
            self, output, size=None, seconds=None,
            first_frame=PiVideoFrameType.sps_header):
        """
        Copies content from the stream to *output*.

        By default, this method copies all complete frames from the circular
        stream to the filename or file-like object given by *output*.

        If *size* is specified then the copy will be limited to the whole
        number of frames that fit within the specified number of bytes. If
        *seconds* if specified, then the copy will be limited to that number of
        seconds worth of frames. Only one of *size* or *seconds* can be
        specified.  If neither is specified, all frames are copied.

        If *first_frame* is specified, it defines the frame type of the first
        frame to be copied. By default this is
        :attr:`~PiVideoFrameType.sps_header` as this must usually be the first
        frame in an H264 stream. If *first_frame* is ``None``, not such limit
        will be applied.

        .. warning::

            Note that if a frame of the specified type (e.g. SPS header) cannot
            be found within the specified number of seconds or bytes then this
            method will simply copy nothing (but no error will be raised).

        The stream's position is not affected by this method.
        """
        if size is not None and seconds is not None:
            raise PiCameraValueError('You cannot specify both size and seconds')
        if isinstance(output, bytes):
            output = output.decode('utf-8')
        opened = isinstance(output, str)
        if opened:
            output = io.open(output, 'wb')
        try:
            with self.lock:
                save_pos = self.tell()
                try:
                    if size is not None:
                        pos = self._find_size(size, first_frame)
                    elif seconds is not None:
                        pos = self._find_seconds(seconds, first_frame)
                    else:
                        pos = self._find_all(first_frame)
                    # Copy chunks efficiently from the position found
                    if pos is not None:
                        self.seek(pos)
                        while True:
                            buf = self.read1()
                            if not buf:
                                break
                            output.write(buf)
                finally:
                    self.seek(save_pos)
        finally:
            if opened:
                output.close()
Beispiel #5
0
 def _set_rotation(self, value):
     try:
         value = ((int(value) % 360) // 90) * 90
     except ValueError:
         raise PiCameraValueError("Invalid rotation angle: %s" % value)
     self._set_transform(
         self._get_transform(value, self._vflip, self._hflip))
     self._rotation = value
Beispiel #6
0
 def __init__(self, camera, splitter_port=1):
     super(PiCameraDequeHack, self).__init__()
     try:
         camera._encoders
     except AttributeError:
         raise PiCameraValueError('camera must be a valid PiCamera object')
     self.camera = camera
     self.splitter_port = splitter_port
Beispiel #7
0
    def _create_encoder(self, quality=85, thumbnail=(64, 48, 35), bayer=False):
        super(PiImageEncoder, self)._create_encoder()

        try:
            self.output_port[0].format[0].encoding = {
                'jpeg': mmal.MMAL_ENCODING_JPEG,
                'png':  mmal.MMAL_ENCODING_PNG,
                'gif':  mmal.MMAL_ENCODING_GIF,
                'bmp':  mmal.MMAL_ENCODING_BMP,
                }[self.format]
        except KeyError:
            raise PiCameraValueError("Unrecognized format %s" % self.format)
        mmal_check(
            mmal.mmal_port_format_commit(self.output_port),
            prefix="Unable to set format on encoder output port")

        if self.format == 'jpeg':
            mmal_check(
                mmal.mmal_port_parameter_set_uint32(
                    self.output_port,
                    mmal.MMAL_PARAMETER_JPEG_Q_FACTOR,
                    quality),
                prefix="Failed to set JPEG quality")

            mmal_check(
                mmal.mmal_port_parameter_set_boolean(
                    self.camera_port,
                    mmal.MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
                    int(bool(bayer))),
                prefix="Failed to set raw capture")

            if thumbnail is None:
                mp = mmal.MMAL_PARAMETER_THUMBNAIL_CONFIG_T(
                    mmal.MMAL_PARAMETER_HEADER_T(
                        mmal.MMAL_PARAMETER_THUMBNAIL_CONFIGURATION,
                        ct.sizeof(mmal.MMAL_PARAMETER_THUMBNAIL_CONFIG_T)
                        ),
                    0, 0, 0, 0)
            else:
                mp = mmal.MMAL_PARAMETER_THUMBNAIL_CONFIG_T(
                    mmal.MMAL_PARAMETER_HEADER_T(
                        mmal.MMAL_PARAMETER_THUMBNAIL_CONFIGURATION,
                        ct.sizeof(mmal.MMAL_PARAMETER_THUMBNAIL_CONFIG_T)
                        ),
                    1, *thumbnail)
            mmal_check(
                mmal.mmal_port_parameter_set(self.encoder[0].control, mp.hdr),
                prefix="Failed to set thumbnail configuration")

        mmal_check(
            mmal.mmal_component_enable(self.encoder),
            prefix="Unable to enable encoder component")
Beispiel #8
0
 def _set_crop(self, value):
     try:
         x, y, w, h = value
     except (TypeError, ValueError) as e:
         raise PiCameraValueError(
             "Invalid crop rectangle (x, y, w, h) tuple: %s" % value)
     mp = mmal.MMAL_DISPLAYREGION_T(
         mmal.MMAL_PARAMETER_HEADER_T(mmal.MMAL_PARAMETER_DISPLAYREGION,
                                      ct.sizeof(mmal.MMAL_DISPLAYREGION_T)),
         set=mmal.MMAL_DISPLAY_SET_SRC_RECT,
         src_rect=mmal.MMAL_RECT_T(x, y, w, h),
     )
     mmal_check(mmal.mmal_port_parameter_set(self.renderer[0].input[0],
                                             mp.hdr),
                prefix="Failed to set crop")
 def bytes_to_rgba(self, data, resolution):
     ''' Converts a bytes objects containing RGBA/BGRA data to a `numpy`_ array.  i.e. this is the 4 byte per pixel version.
         It's here as a class method to keep things neat - the 3-byte-per-pixel version is a module function. i.e. picamera.array.bytes_to_rgb()
     '''
     width, height = resolution
     fwidth, fheight = picamera.array.raw_resolution(resolution)
     # Workaround: output from the video splitter is rounded to 16x16 instead
     # of 32x16 (but only for RGB, and only when a resizer is not used)
     bpp = 4
     if len(data) != (fwidth * fheight * bpp):
         fwidth, fheight = picamera.array.raw_resolution(resolution,
                                                         splitter=True)
         if len(data) != (fwidth * fheight * bpp):
             raise PiCameraValueError(
                 'Incorrect buffer length for resolution %dx%d' %
                 (width, height))
     # Crop to the actual resolution
     return np.frombuffer(data, dtype=np.uint8).reshape(
         (fheight, fwidth, bpp))[:height, :width, :]
Beispiel #10
0
    def copy_to_stream(self,
                       size=None,
                       seconds=None,
                       first_frame=PiVideoFrameType.sps_header):
        if size is not None and seconds is not None:
            raise PiCameraValueError(
                'You cannot specify both size and seconds')

        stream = BytesIO()

        with self.lock:
            save_pos = self.tell()

            try:
                if size is not None:
                    pos = self._find_size(size, first_frame)
                elif seconds is not None:
                    pos = self._find_seconds(seconds, first_frame)
                else:
                    pos = self._find_all(first_frame)

                if pos is not None:
                    self.seek(pos)

                    while True:
                        buf = self.read1()

                        if not buf:
                            break

                        stream.write(buf)

            finally:
                self.seek(save_pos)

        stream.seek(0)
        return stream
Beispiel #11
0
    def _create_encoder(self,
                        bitrate=17000000,
                        intra_period=0,
                        profile='high',
                        quantization=0,
                        inline_headers=True,
                        sei=False):
        super(PiVideoEncoder, self)._create_encoder()

        try:
            self.output_port[0].format[0].encoding = {
                'h264': mmal.MMAL_ENCODING_H264,
                'mjpeg': mmal.MMAL_ENCODING_MJPEG,
            }[self.format]
        except KeyError:
            raise PiCameraValueError('Unrecognized format %s' % self.format)

        if not (0 <= bitrate <= 25000000):
            raise PiCameraValueError(
                'bitrate must be between 0 (VBR) and 25Mbps')
        if quantization and bitrate:
            warnings.warn('Setting bitrate to 0 as quantization is non-zero',
                          PiCameraWarning)
            bitrate = 0
        self.output_port[0].format[0].bitrate = bitrate
        mmal_check(mmal.mmal_port_format_commit(self.output_port),
                   prefix="Unable to set format on encoder output port")

        if self.format == 'h264':
            mp = mmal.MMAL_PARAMETER_VIDEO_PROFILE_T(
                mmal.MMAL_PARAMETER_HEADER_T(
                    mmal.MMAL_PARAMETER_PROFILE,
                    ct.sizeof(mmal.MMAL_PARAMETER_VIDEO_PROFILE_T),
                ), )
            try:
                mp.profile[0].profile = {
                    'baseline':
                    mmal.MMAL_VIDEO_PROFILE_H264_BASELINE,
                    'main':
                    mmal.MMAL_VIDEO_PROFILE_H264_MAIN,
                    'high':
                    mmal.MMAL_VIDEO_PROFILE_H264_HIGH,
                    'constrained':
                    mmal.MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
                }[profile]
            except KeyError:
                raise PiCameraValueError("Invalid H.264 profile %s" % profile)
            mp.profile[0].level = mmal.MMAL_VIDEO_LEVEL_H264_4
            mmal_check(mmal.mmal_port_parameter_set(self.output_port, mp.hdr),
                       prefix="Unable to set encoder H.264 profile")

            mmal_check(mmal.mmal_port_parameter_set_boolean(
                self.output_port,
                mmal.MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
                int(inline_headers)),
                       prefix="Unable to set inline_headers")

            mmal_check(mmal.mmal_port_parameter_set_boolean(
                self.output_port, mmal.MMAL_PARAMETER_VIDEO_ENCODE_SEI_ENABLE,
                int(sei)),
                       prefix="Enable to set SEI")

            if not (bitrate and inline_headers):
                # If inline_headers is disabled, or VBR encoding is configured,
                # disable the split function
                self._next_output = None

            if intra_period:
                mp = mmal.MMAL_PARAMETER_UINT32_T(
                    mmal.MMAL_PARAMETER_HEADER_T(
                        mmal.MMAL_PARAMETER_INTRAPERIOD,
                        ct.sizeof(mmal.MMAL_PARAMETER_UINT32_T),
                    ), intra_period)
                mmal_check(mmal.mmal_port_parameter_set(
                    self.output_port, mp.hdr),
                           prefix="Unable to set encoder intra_period")

        if quantization:
            mp = mmal.MMAL_PARAMETER_UINT32_T(
                mmal.MMAL_PARAMETER_HEADER_T(
                    mmal.MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
                    ct.sizeof(mmal.MMAL_PARAMETER_UINT32_T),
                ), quantization)
            mmal_check(mmal.mmal_port_parameter_set(self.output_port, mp.hdr),
                       prefix="Unable to set initial quantization")
            mp = mmal.MMAL_PARAMETER_UINT32_T(
                mmal.MMAL_PARAMETER_HEADER_T(
                    mmal.MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
                    ct.sizeof(mmal.MMAL_PARAMETER_UINT32_T),
                ),
                quantization,
            )
            mmal_check(mmal.mmal_port_parameter_set(self.output_port, mp.hdr),
                       prefix="Unable to set minimum quantization")
            mp = mmal.MMAL_PARAMETER_UINT32_T(
                mmal.MMAL_PARAMETER_HEADER_T(
                    mmal.MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
                    ct.sizeof(mmal.MMAL_PARAMETER_UINT32_T),
                ),
                quantization,
            )
            mmal_check(mmal.mmal_port_parameter_set(self.output_port, mp.hdr),
                       prefix="Unable to set maximum quantization")

        mmal_check(mmal.mmal_port_parameter_set_boolean(
            self.encoder[0].input[0],
            mmal.MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, 1),
                   prefix="Unable to set immutable flag on encoder input port")

        mmal_check(mmal.mmal_component_enable(self.encoder),
                   prefix="Unable to enable video encoder component")
Beispiel #12
0
    def copy_to(self,
                output,
                size=None,
                seconds=None,
                frames=None,
                first_frame=PiVideoFrameType.sps_header,
                match=False):
        """
        copy_to(output, size=None, seconds=None, frames=None, first_frame=PiVideoFrameType.sps_header)

        Copies content from the stream to *output*.

        By default, this method copies all complete frames from the circular
        stream to the filename or file-like object given by *output*.

        If *size* is specified then the copy will be limited to the whole
        number of frames that fit within the specified number of bytes. If
        *seconds* if specified, then the copy will be limited to that number of
        seconds worth of frames. If *frames* is specified then the copy will
        be limited to that number of frames. Only one of *size*, *seconds*, or
        *frames* can be specified. If none is specified, all frames are copied.

        If *first_frame* is specified, it defines the frame type of the first
        frame to be copied. By default this is
        :attr:`~PiVideoFrameType.sps_header` as this must usually be the first
        frame in an H264 stream. If *first_frame* is ``None``, not such limit
        will be applied.

        If *match* is true and *size*, *seconds* or *frames* is specified then
        the copy will be limited to the whole number of frames that matches or
        exceeds the given criteria by less than one frame.

        .. warning::

            Note that if a frame of the specified type (e.g. SPS header) cannot
            be found within the specified number of seconds, bytes, or frames,
            then this method will simply copy nothing (but no error will be
            raised).

        The stream's position is not affected by this method.
        """
        if (size, seconds, frames).count(None) < 2:
            raise PiCameraValueError(
                'You can only specify one of size, seconds, or frames')
        if isinstance(output, bytes):
            output = output.decode('utf-8')
        opened = isinstance(output, str)
        if opened:
            output = io.open(output, 'wb')
        try:
            with self.lock:
                if size is not None:
                    first, last = self._find('video_size', size, first_frame,
                                             match)
                elif seconds is not None:
                    seconds = int(seconds * 1000000)
                    first, last = self._find('timestamp', seconds, first_frame,
                                             match)
                elif frames is not None:
                    first, last = self._find('index', frames, first_frame,
                                             match)
                else:
                    first, last = self._find_all(first_frame)
                # Copy chunk references into a holding buffer; this allows us
                # to release the lock on the stream quickly (in case recording
                # is on-going)
                chunks = []
                if first is not None and last is not None:
                    pos = 0
                    for buf, frame in self._data.iter_both(False):
                        if pos > last.position + last.frame_size:
                            break
                        elif pos >= first.position:
                            chunks.append(buf)
                        pos += len(buf)
            # Perform the actual I/O, copying chunks to the output
            for buf in chunks:
                output.write(buf)
            return first, last
        finally:
            if opened:
                output.close()