Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bububa committed Oct 8, 2021
1 parent 776b31c commit d34c760
Show file tree
Hide file tree
Showing 27 changed files with 966 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Go

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:

build:
runs-on: ubuntu-latest
steps:
- name: Checkout github repo (+ download lfs dependencies)
uses: actions/checkout@v2
with:
lfs: true

- name: Checkout LFS objects
run: git lfs checkout

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17

- name: Build
run: |
go build -tags=jpeg,linux -v ./...
- name: Test
run: |
go test -v ./...
16 changes: 16 additions & 0 deletions .github/workflows/goformatter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Golang Formatter
on: [pull_request]
jobs:
build:
name: Golang Formatter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 0

- name: Golang Formatter
uses: sladyn98/auto-go-format@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

36 changes: 36 additions & 0 deletions .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: goreleaser

on:
push:
tags:
- '*'

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
lfs: true

- name: Checkout LFS objects
run: git lfs checkout

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
9 changes: 9 additions & 0 deletions .github/workflows/goreportcard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: GoReportCard
on: [push, pull_request]
jobs:
build:
name: GoReportCard
runs-on: ubuntu-latest
steps:
- name: GoReportCard
uses: creekorful/goreportcard-action@v1.0
27 changes: 27 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This is an example .goreleaser.yml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
project_name: "camera"
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
- skip: true
archives:
- replacements:
darwin: Darwin
linux: Linux
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
255 changes: 255 additions & 0 deletions android/camera.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
//go:build android
// +build android

package android

/*
#include <android/log.h>
#include <media/NdkImageReader.h>
#include <camera/NdkCameraDevice.h>
#include <camera/NdkCameraManager.h>
#define TAG "camera"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
AImage *image;
AImageReader *imageReader;
ANativeWindow *nativeWindow;
ACameraDevice *cameraDevice;
ACameraManager *cameraManager;
ACameraOutputTarget *cameraOutputTarget;
ACameraCaptureSession *cameraCaptureSession;
ACaptureRequest *captureRequest;
ACaptureSessionOutput *captureSessionOutput;
ACaptureSessionOutputContainer *captureSessionOutputContainer;
void device_on_disconnected(void *context, ACameraDevice *device) {
LOGI("camera %s is diconnected.\n", ACameraDevice_getId(device));
}
void device_on_error(void *context, ACameraDevice *device, int error) {
LOGE("error %d on camera %s.\n", error, ACameraDevice_getId(device));
}
ACameraDevice_stateCallbacks deviceStateCallbacks = {
.context = NULL,
.onDisconnected = device_on_disconnected,
.onError = device_on_error,
};
void session_on_ready(void *context, ACameraCaptureSession *session) {
LOGI("session is ready. %p\n", session);
}
void session_on_active(void *context, ACameraCaptureSession *session) {
LOGI("session is activated. %p\n", session);
}
void session_on_closed(void *context, ACameraCaptureSession *session) {
LOGI("session is closed. %p\n", session);
}
ACameraCaptureSession_stateCallbacks captureSessionStateCallbacks = {
.context = NULL,
.onActive = session_on_active,
.onReady = session_on_ready,
.onClosed = session_on_closed,
};
void image_callback(void *context, AImageReader *reader) {
LOGD("image_callback");
media_status_t status = AImageReader_acquireLatestImage(reader, &image);
if(status != AMEDIA_OK) {
LOGE("failed to acquire next image (reason: %d).\n", status);
}
}
AImageReader_ImageListener imageListener = {
.context = NULL,
.onImageAvailable = image_callback,
};
int openCamera(int index, int width, int height) {
ACameraIdList *cameraIdList;
const char *selectedCameraId;
camera_status_t status = ACAMERA_OK;
cameraManager = ACameraManager_create();
status = ACameraManager_getCameraIdList(cameraManager, &cameraIdList);
if(status != ACAMERA_OK) {
LOGE("failed to get camera id list (reason: %d).\n", status);
return status;
}
if(cameraIdList->numCameras < 1) {
LOGE("no camera device detected.\n");
}
if(cameraIdList->numCameras < index+1) {
LOGE("no camera at index %d.\n", index);
}
selectedCameraId = cameraIdList->cameraIds[index];
LOGI("open camera (id: %s, num of cameras: %d).\n", selectedCameraId, cameraIdList->numCameras);
status = ACameraManager_openCamera(cameraManager, selectedCameraId, &deviceStateCallbacks, &cameraDevice);
if(status != ACAMERA_OK) {
LOGE("failed to open camera device (id: %s)\n", selectedCameraId);
return status;
}
status = ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_STILL_CAPTURE, &captureRequest);
if(status != ACAMERA_OK) {
LOGE("failed to create snapshot capture request (id: %s)\n", selectedCameraId);
return status;
}
status = ACaptureSessionOutputContainer_create(&captureSessionOutputContainer);
if(status != ACAMERA_OK) {
LOGE("failed to create session output container (id: %s)\n", selectedCameraId);
return status;
}
media_status_t mstatus = AImageReader_new(width, height, AIMAGE_FORMAT_YUV_420_888, 2, &imageReader);
if(mstatus != AMEDIA_OK) {
LOGE("failed to create image reader (reason: %d).\n", mstatus);
return mstatus;
}
mstatus = AImageReader_setImageListener(imageReader, &imageListener);
if(mstatus != AMEDIA_OK) {
LOGE("failed to set image listener (reason: %d).\n", mstatus);
return mstatus;
}
AImageReader_getWindow(imageReader, &nativeWindow);
ANativeWindow_acquire(nativeWindow);
ACameraOutputTarget_create(nativeWindow, &cameraOutputTarget);
ACaptureRequest_addTarget(captureRequest, cameraOutputTarget);
ACaptureSessionOutput_create(nativeWindow, &captureSessionOutput);
ACaptureSessionOutputContainer_add(captureSessionOutputContainer, captureSessionOutput);
status = ACameraDevice_createCaptureSession(cameraDevice, captureSessionOutputContainer, &captureSessionStateCallbacks, &cameraCaptureSession);
if(status != ACAMERA_OK) {
LOGE("failed to create capture session (reason: %d).\n", status);
return status;
}
ACameraManager_deleteCameraIdList(cameraIdList);
ACameraManager_delete(cameraManager);
return ACAMERA_OK;
}
int captureCamera() {
camera_status_t status = ACameraCaptureSession_capture(cameraCaptureSession, NULL, 1, &captureRequest, NULL);
if(status != ACAMERA_OK) {
LOGE("failed to capture image (reason: %d).\n", status);
}
return status;
}
int closeCamera() {
camera_status_t status = ACAMERA_OK;
if(captureRequest != NULL) {
ACaptureRequest_free(captureRequest);
captureRequest = NULL;
}
if(cameraOutputTarget != NULL) {
ACameraOutputTarget_free(cameraOutputTarget);
cameraOutputTarget = NULL;
}
if(cameraDevice != NULL) {
status = ACameraDevice_close(cameraDevice);
if(status != ACAMERA_OK) {
LOGE("failed to close camera device.\n");
return status;
}
cameraDevice = NULL;
}
if(captureSessionOutput != NULL) {
ACaptureSessionOutput_free(captureSessionOutput);
captureSessionOutput = NULL;
}
if(captureSessionOutputContainer != NULL) {
ACaptureSessionOutputContainer_free(captureSessionOutputContainer);
captureSessionOutputContainer = NULL;
}
if(imageReader != NULL) {
AImageReader_delete(imageReader);
imageReader = NULL;
}
if(image != NULL) {
AImage_delete(image);
image = NULL;
}
LOGI("camera closed.\n");
return ACAMERA_OK;
}
int openCamera(int index, int width, int height);
int captureCamera();
int closeCamera();
#cgo android CFLAGS: -D__ANDROID_API__=24
#cgo android LDFLAGS: -lcamera2ndk -lmediandk -llog -landroid
*/
import "C"

import (
"fmt"
"image"
"unsafe"

"github.com/bububa/facenet/camera"
)

// Camera represents camera.
type Camera struct {
opts camera.Options
img *image.YCbCr
}

// New returns new Camera for given camera index.
func New(opts Options) (camera *Camera, err error) {
camera = &Camera{}
camera.opts = opts

camera.img = image.NewYCbCr(image.Rect(0, 0, int(opts.Width), int(opts.Height)), image.YCbCrSubsampleRatio420)

ret := C.openCamera(C.int(opts.Index), C.int(opts.Width), C.int(opts.Height))
if bool(int(ret) != 0) {
err = fmt.Errorf("camera: can not open camera %d: error %d", opts.Index, int(ret))
return
}

return
}

// Read reads next frame from camera and returns image.
func (c *Camera) Read() (img image.Image, err error) {
ret := C.captureCamera()
if bool(int(ret) != 0) {
err = fmt.Errorf("camera: can not grab frame: error %d", int(ret))
return
}

if C.image == nil {
err = fmt.Errorf("camera: can not retrieve frame")
return
}

var yStride C.int
var yLen, cbLen, crLen C.int
var yPtr, cbPtr, crPtr *C.uint8_t

C.AImage_getPlaneRowStride(C.image, 0, &yStride)
C.AImage_getPlaneData(C.image, 0, &yPtr, &yLen)
C.AImage_getPlaneData(C.image, 1, &cbPtr, &cbLen)
C.AImage_getPlaneData(C.image, 2, &crPtr, &crLen)

c.img.YStride = int(yStride)
c.img.CStride = int(yStride) / 2

c.img.Y = C.GoBytes(unsafe.Pointer(yPtr), yLen)
c.img.Cb = C.GoBytes(unsafe.Pointer(cbPtr), cbLen)
c.img.Cr = C.GoBytes(unsafe.Pointer(crPtr), crLen)

img = c.img

return
}

// GetProperty returns the specified camera property.
func (c *Camera) GetProperty(id int) float64 {
return 0
}

// SetProperty sets a camera property.
func (c *Camera) SetProperty(id int, value float64) {
}

// Close closes camera.
func (c *Camera) Close() (err error) {
ret := C.closeCamera()
if bool(int(ret) != 0) {
err = fmt.Errorf("camera: can not close camera %d: error %d", c.opts.Index, int(ret))
return
}

return
}
5 changes: 5 additions & 0 deletions android/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build android
// +build android

// Package android for android device
package android

0 comments on commit d34c760

Please sign in to comment.