Picam is a library that provides a simple API for streaming MJPEG video and capturing JPEG stills using the camera module on Raspberry Pi devices running Linux.

camera, elixir, mjpeg, nerves-project, raspberry-pi, video



Hex version

Picam is an Elixir library that provides a simple API for streaming MJPEG video and capturing JPEG stills using the camera module on Raspberry Pi devices running Linux.

Features currently supported by the API:

  • Set sharpness, contrast, brightness, saturation, ISO, and shutter speed values
  • Set the exposure, sensor, metering, and white balance modes
  • Set image and color effects
  • Rotate and flip the image vertically and horizontally
  • Set the exposure compensation (EV) level
  • Change the image size
  • Adjust JPEG fidelity through quality level, restart intervals, and region of interest
  • Enable or disable video stabilization
  • Adjust the video framerate
  • Render fullscreen or windowed video preview to HDMI and CSI displays

For specifics on the above features, please consult the Hex docs.


Requirement Notes
Host Device Raspberry Pi 1, 2, 3, Zero/W Zero and Zero W require a special ribbon cable
Operating System Linux Works out of the box with Raspian and Nerves builds
Camera Module V1, V2 Regular, NoIR. Note for V2 module, gpu_mem in /boot/config.txt must be set >= 192
C Libraries Broadcom VideoCore Located in /opt/vc by default. Override with VIDEOCORE_DIR


The package can be installed by adding picam to your list of dependencies in mix.exs:

def deps do
  [{:picam, "~> 0.4.0"}]


Picam uses a port application named raspijpgs that interfaces with the underlying Multi-Media Abstraction Layer (MMAL) API in VideoCore. The port is started by the Picam.Camera process.

For example, to write a JPEG still using the :sketch image effect to /tmp/frame.jpg:

iex(1)> Picam.Camera.start_link
{:ok, #PID<0.160.0>}

iex(2)> Picam.set_img_effect(:sketch)

iex(3)> Picam.set_size(640, 0) # 0 automatically calculates height

iex(4)> File.write!(Path.join(System.tmp_dir!, "frame.jpg"), Picam.next_frame)

iex(5)> Picam.set_img_effect(:none) # Disable the effect

If you receive an :unexpected_exit error immediately after starting the Picam.Camera process and you're using a V2 camera module, please check that you've set gpu_mem to a value >= 192 in /boot/config.txt. You can verify this has taken effect in your terminal using vcgencmd get_mem gpu.

More than likely you'll want to put the Picam.Camera process in your supervision tree rather than starting it manually:

# lib/my_app/application.ex

children = [
  worker(Picam.Camera, []),
  # ...

Faking the camera for development and testing

In order to facilitate running in dev and test modes on your development host, you can override the real Picam.Camera worker with Picam.FakeCamera by setting the :camera config option:

# config.exs

# ...

import_config "#{Mix.Project.config[:target]}.exs"
# config/host.exs

use Mix.Config
config :picam, camera: Picam.FakeCamera

This will cause Picam to use the FakeCamera back-end instead of the real Camera back-end, which streams a static image of the specified size at approximately the specified fps rate (using a naïve sleep-based delay between frames). In order for this to work, you will need to make sure you are staring the matching worker for your environment:

# lib/my_app/application.ex

camera = Application.get_env(:picam, :camera, Picam.Camera)

children = [
  worker(camera, []),
  # ...

When using the FakeCamera, all the normal Picam API commands will be validated but silently ignored, with the following exceptions:

  • Picam.set_fps/1 will set the desired frame rate (in frames per second)

  • Picam.set_size/2 only has static images built-in for the following resolutions:

    • 1920 x 1080
    • 1280 x 720
    • 640 x 480

    If any other resolution is specified, the static image will default back to 1280 x 720. If you want to test with an image of a particular size or with specific image contents, you can specify your own image with Picam.FakeCamera.set_image/1, which accepts a JPEG-encoded binary.

    For example:

    |> File.read!()
    |> Picam.FakeCamera.set_image()


The examples directory is where you can find other useful demos of Picam in action. More examples will be added over time.

Directory Demo
picam_http Streaming MJPEG video using plug


  • Currently only one camera is supported. If you intend to use more than one camera through an add-on compute module, please submit an issue.

Copyright and License

Copyright (c) 2013-2017, Broadcom Europe Ltd, Silvan Melchior, James Hughes, Frank Hunleth, Jeff Smith

Picam source code is licensed under the BSD 3-Clause License.