Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1553,7 +1553,7 @@ msgstr ""

#: ports/espressif/common-hal/audioio/AudioOut.c
#: ports/espressif/common-hal/mipicsi/Camera.c
#: shared-module/videocore/VideoBuffer.c
#: shared-module/videocore/VideoBuffer.c shared-module/videogif/GifDecoder.c
msgid "already playing"
msgstr ""

Expand Down
9 changes: 9 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
#include "shared-module/usb_host_audio/USBIn.h"
#endif

#if CIRCUITPY_VIDEOGIF
#include "shared-module/videogif/GifDecoder.h"
#endif

#if CIRCUITPY_MEMORYMONITOR
#include "shared-module/memorymonitor/__init__.h"
#endif
Expand Down Expand Up @@ -392,6 +396,11 @@ static void cleanup_after_vm(mp_obj_t exception) {
picogame_reset();
#endif

// Stop GIF playback before the displays and their framebuffers go away.
#if CIRCUITPY_VIDEOGIF
videogif_reset();
#endif

// Turn off the display and flush the filesystem before the heap disappears.
#if CIRCUITPY_DISPLAYIO
reset_displays();
Expand Down
4 changes: 2 additions & 2 deletions ports/espressif/common-hal/mipicsi/Camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ static IRAM_ATTR bool mipicsi_on_trans_finished(
// Report where the frame actually landed: after a destination change
// (or a pause) the frame that was in flight lands at the previous one.
if (self->dest_base != NULL && self->dest_on_frame != NULL) {
self->dest_on_frame(self->dest_ctx, trans->buffer);
self->dest_on_frame(self->dest_ctx, trans->buffer, NULL);
}
return false;
}
Expand Down Expand Up @@ -406,7 +406,7 @@ bool common_hal_mipicsi_camera_set_destination(
mipicsi_camera_obj_t *self,
uint8_t *base,
size_t stride,
void (*on_frame)(void *ctx, const void *frame),
videocore_on_frame_fun on_frame,
void *ctx) {
const size_t row_bytes = ((size_t)self->width * mipicsi_bits_per_pixel_for(self->output_format) + 7) / 8;
const size_t frame_bytes = (size_t)self->height * row_bytes;
Expand Down
7 changes: 4 additions & 3 deletions ports/espressif/common-hal/mipicsi/Camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#endif

#include "shared-bindings/mipicsi/__init__.h"
#include "shared-module/videocore/__init__.h"

typedef struct mipicsi_camera_obj mipicsi_camera_obj_t;

Expand Down Expand Up @@ -56,10 +57,10 @@ struct mipicsi_camera_obj {
// Streaming destination, set by videocore.VideoBuffer. The CSI controller
// only runs while dest_base is set. Frames are DMA'd contiguously into
// dest_base, which must be cache-line aligned. dest_on_frame(dest_ctx,
// frame) is called from the ISR with where each frame landed; a frame in
// flight when the destination changes lands at the previous one.
// frame, NULL) is called from the ISR with where each frame landed; a
// frame in flight when the destination changes lands at the previous one.
volatile void *dest_base;
void (*dest_on_frame)(void *ctx, const void *frame);
videocore_on_frame_fun dest_on_frame;
void *dest_ctx;
bool ctlr_started;
// True between pause and resume: only the CSI controller is stopped.
Expand Down
5 changes: 5 additions & 0 deletions py/circuitpy_defns.mk
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,9 @@ endif
ifeq ($(CIRCUITPY_VIDEOCORE),1)
SRC_PATTERNS += videocore/%
endif
ifeq ($(CIRCUITPY_VIDEOGIF),1)
SRC_PATTERNS += videogif/%
endif
ifeq ($(CIRCUITPY_WARNINGS),1)
SRC_PATTERNS += warnings/%
endif
Expand Down Expand Up @@ -719,6 +722,7 @@ $(filter $(SRC_PATTERNS), \
supervisor/RunReason.c \
supervisor/Runtime.c \
supervisor/StatusBar.c \
videogif/__init__.c \
wifi/AuthMode.c \
wifi/Packet.c \
wifi/PowerManagement.c \
Expand Down Expand Up @@ -926,6 +930,7 @@ SRC_SHARED_MODULE_ALL = \
vectorio/__init__.c \
videocore/VideoBuffer.c \
videocore/__init__.c \
videogif/GifDecoder.c \
warnings/__init__.c \
watchdog/__init__.c \
zlib/__init__.c \
Expand Down
4 changes: 4 additions & 0 deletions py/circuitpy_mpconfig.mk
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,10 @@ CIRCUITPY_ULAB_OPTIMIZE_SIZE ?= 0
CIRCUITPY_VIDEOCORE ?= 0
CFLAGS += -DCIRCUITPY_VIDEOCORE=$(CIRCUITPY_VIDEOCORE)

# Animated GIF files as a videocore video source. Shares gifio's decoder.
CIRCUITPY_VIDEOGIF ?= $(call enable-if-all,$(CIRCUITPY_VIDEOCORE) $(CIRCUITPY_GIFIO))
CFLAGS += -DCIRCUITPY_VIDEOGIF=$(CIRCUITPY_VIDEOGIF)

CIRCUITPY_WARNINGS ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_WARNINGS=$(CIRCUITPY_WARNINGS)

Expand Down
20 changes: 12 additions & 8 deletions shared-bindings/gifio/OnDiskGif.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
#include "shared-bindings/util.h"
#include "shared-bindings/gifio/OnDiskGif.h"

mp_obj_t gifio_open_file(mp_obj_t file) {
if (mp_obj_is_str(file)) {
file = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), file, MP_ROM_QSTR(MP_QSTR_rb));
}

if (!mp_obj_is_fileio(file)) {
mp_raise_TypeError(MP_ERROR_TEXT("file must be a file opened in byte mode"));
}
return file;
}

//| class OnDiskGif:
//| """Loads one frame of a GIF into memory at a time.
//|
Expand Down Expand Up @@ -113,14 +124,7 @@ static mp_obj_t gifio_ondiskgif_make_new(const mp_obj_type_t *type, size_t n_arg
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

mp_obj_t filename = args[ARG_filename].u_obj;
if (mp_obj_is_str(filename)) {
filename = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), filename, MP_ROM_QSTR(MP_QSTR_rb));
}

if (!mp_obj_is_fileio(filename)) {
mp_raise_TypeError(MP_ERROR_TEXT("file must be a file opened in byte mode"));
}
mp_obj_t filename = gifio_open_file(args[ARG_filename].u_obj);

gifio_ondiskgif_t *self = mp_obj_malloc_with_finaliser(gifio_ondiskgif_t, &gifio_ondiskgif_type);
common_hal_gifio_ondiskgif_construct(self, filename, args[ARG_use_palette].u_bool);
Expand Down
4 changes: 4 additions & 0 deletions shared-bindings/gifio/OnDiskGif.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@

extern const mp_obj_type_t gifio_ondiskgif_type;

// Return file, opened for reading in binary mode when it is a file name.
// Raises TypeError unless the result is a file opened in binary mode.
mp_obj_t gifio_open_file(mp_obj_t file);

void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, mp_obj_t file, bool use_palette);

uint32_t common_hal_gifio_ondiskgif_get_pixel(gifio_ondiskgif_t *bitmap,
Expand Down
2 changes: 1 addition & 1 deletion shared-bindings/mipicsi/Camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ bool common_hal_mipicsi_camera_set_destination(
mipicsi_camera_obj_t *self,
uint8_t *base,
size_t stride,
void (*on_frame)(void *ctx, const void *frame),
videocore_on_frame_fun on_frame,
void *ctx);

mipicsi_pixel_format_t common_hal_mipicsi_camera_get_pixel_format(mipicsi_camera_obj_t *self);
Expand Down
8 changes: 6 additions & 2 deletions shared-bindings/videocore/VideoBuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ static mp_obj_t videocore_videobuffer_make_new(const mp_obj_type_t *type, size_t
//| whole frame.
//|
//| :param ~circuitpython_typing.VideoSource source: The video source to
//| play, such as `mipicsi.Camera`
//| play, such as `mipicsi.Camera` or `videogif.GifDecoder`
//| """
//|
static mp_obj_t videocore_videobuffer_play(mp_obj_t self_in, mp_obj_t source) {
Expand All @@ -103,7 +103,11 @@ static mp_obj_t videocore_videobuffer_stop(mp_obj_t self_in) {
static MP_DEFINE_CONST_FUN_OBJ_1(videocore_videobuffer_stop_obj, videocore_videobuffer_stop);

//| playing: bool
//| """True when a video source is being played, False otherwise. (read-only)"""
//| """True when a video source is being played, False otherwise. It also
//| becomes False when the source has no more frames, such as a GIF that
//| has finished its last loop. The last frame then stays shown until
//| ``stop()`` or the next ``play()``. A framebuffer target also drops it
//| when moved or hidden. (read-only)"""
//|
static mp_obj_t videocore_videobuffer_get_playing(mp_obj_t self_in) {
videocore_videobuffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
Expand Down
7 changes: 4 additions & 3 deletions shared-bindings/videocore/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
//| This module provides the video pipeline shared between video sources and
//| video outputs. It is the video equivalent of the `audiocore` module.
//|
//| Video sources, such as `mipicsi.Camera`, implement the internal videosource
//| protocol. A `VideoBuffer` tells a video source where to put its frames in a
//| framebuffer, such as `mipidsi.Display`, and can move it as needed.
//| A video source, such as `mipicsi.Camera` or `videogif.GifDecoder`, makes
//| video frames. A `VideoBuffer` plays a video source and tells it where to
//| put each frame: in a display's memory, such as `mipidsi.Display`, or in a
//| ``bytearray`` that a displayio Group shows.
//|
//| Stream a MIPI CSI camera live into the board's display (a MIPI DSI panel
//| on ESP32-P4-Function-EV, for example):
Expand Down
Loading
Loading