Skip to content

Commit

Permalink
Import files
Browse files Browse the repository at this point in the history
  • Loading branch information
iizukanao committed Jan 10, 2014
1 parent a90b58d commit 508f8e9
Show file tree
Hide file tree
Showing 15 changed files with 3,904 additions and 3 deletions.
23 changes: 23 additions & 0 deletions Makefile
@@ -0,0 +1,23 @@
CC=cc
CFLAGS=-DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -Wall -g -DHAVE_LIBOPENMAX=2 -DOMX -DOMX_SKIP64BIT -ftree-vectorize -pipe -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM -Wno-psabi -I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/src/hello_pi/libs/ilclient -g -Wno-deprecated-declarations -O3 -pipe -march=armv6j -mfpu=vfp -mfloat-abi=hard
LDFLAGS=-g -Wl,--whole-archive -lilclient -L/opt/vc/lib/ -L/usr/local/lib -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -L/opt/vc/src/hello_pi/libs/ilclient -Wl,--no-whole-archive -rdynamic -lavformat -lavcodec -ldl -lasound -lavutil -lm -lfdk-aac -lcrypto -pipe
SOURCES=stream.c hooks.c mpegts.c httplivestreaming.c state.c
HEADERS=config.h hooks.h mpegts.h httplivestreaming.h state.h
OBJECTS=$(SOURCES:.c=.o)
EXECUTABLE=stream.bin

all: $(SOURCES) $(EXECUTABLE)

still: still.c
$(CC) still.c -o still $(CFLAGS) $(LDFLAGS)

$(EXECUTABLE): $(OBJECTS)
$(CC) $(OBJECTS) -o $@ $(LDFLAGS)

%.o: %.c $(HEADERS)
$(CC) -c $< -o $@ $(CFLAGS)

.PHONY: clean

clean:
rm -f $(EXECUTABLE) $(OBJECTS)
51 changes: 48 additions & 3 deletions README.md
@@ -1,4 +1,49 @@
picam
=====
### picam

Capture video from Raspberry Pi Camera and audio from ALSA, then mux them into MPEG-TS and provide HTTP Live Streaming.
#### Features

- Capture video from Raspberry Pi Camera
- Capture audio from USB microphone
- Mux video and audio stream into MPEG-TS format

### Required hardware

- Raspberry Pi
- Raspberry Pi Camera Board
- USB microphone (see [Recommended hardware](#recommended-hardware))

### Installation

#### Install libraries

Build and install these libraries for a Raspberry Pi:

- ffmpeg
- libasound
- libfdk-aac

#### Compile libilclient

On a Raspberry Pi, issue the following command:

$ cd /opt/vc/src/hello_pi/libs/ilclient
$ make

#### Compile picam

$ git clone https://github.com/iizukanao/picam.git
$ cd picam
$ make
$ ./stream.bin

### Recommended hardware

#### USB microphone

In combination with:
- [PLANEX PL-US35AP](http://www.planex.co.jp/product/usb/pl-us35ap/)
- [ELECOM MS-STM95](http://www2.elecom.co.jp/multimedia/microphone/ms-stm95/)

### License

LGPL v2.1, as some parts of FFmpeg source is included.
34 changes: 34 additions & 0 deletions config.h
@@ -0,0 +1,34 @@
#ifndef PICAM_CONFIG_H
#define PICAM_CONFIG_H

#if defined(__cplusplus)
extern "C" {
#endif

// Even if we specify 30 FPS, Raspberry Pi Camera provides slighly lower FPS.
#define TARGET_FPS 30

// For higher resolution
#define H264_BIT_RATE 3000 * 1000 // 3 Mbps

#define GOP_SIZE TARGET_FPS

// Set to 1 if you want to produce audio-only stream for debugging
#define AUDIO_ONLY 0

// 1600x900 is the upper limit if you don't tunnel from camera to video_encode.
// 720p (1280x720) is good enough for most cases.
#define WIDTH 1280
#define HEIGHT 720

#define AAC_BIT_RATE 40000

// Choose the value that results in non-repeating decimal when divided by 90000.
// e.g. 48000 and 32000 are fine, but 44100 and 22050 are bad.
#define AUDIO_SAMPLE_RATE 48000

#if defined(__cplusplus)
}
#endif

#endif
209 changes: 209 additions & 0 deletions hooks.c
@@ -0,0 +1,209 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <pthread.h>
#include <signal.h>
#include <dirent.h>

#include "hooks.h"

#define NUM_EVENT_BUF 10
#define EVENT_NAME_BUF_LEN 32

#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN ( NUM_EVENT_BUF * ( EVENT_SIZE + EVENT_NAME_BUF_LEN ) )

typedef struct watch_target {
char *dir;
void (*callback)(char *, char *);
int read_content;
} watch_target;

static int keep_watching = 1;
static pthread_t *watcher_thread;

void sig_handler(int signum) {
}

int clear_hooks(char *dirname) {
DIR *dir;
struct dirent *ent;
char *path = NULL;
char *new_path;
int path_len;
int dirname_len;
int status = 0;

dirname_len = strlen(dirname);
if ((dir = opendir(dirname)) != NULL) {
while ((ent = readdir(dir)) != NULL) {
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0) {
continue;
}
path_len = dirname_len + strlen(ent->d_name) + 2;
if (path == NULL) {
path = malloc(path_len);
if (path == NULL) {
perror("malloc path failed");
closedir(dir);
return -1;
}
} else {
new_path = realloc(path, path_len);
if (new_path == NULL) {
perror("realloc path failed");
closedir(dir);
return -1;
}
path = new_path;
}
snprintf(path, path_len, "%s/%s", dirname, ent->d_name);
if (unlink(path) != 0) {
perror("unlink failed");
status = -1;
}
}
closedir(dir);
if (path != NULL) {
free(path);
}
} else {
status = -1;
}

return status;
}

void *watch_for_file_creation(watch_target *target) {
int length, i;
int fd;
int wd;
int dir_strlen;
char buffer[EVENT_BUF_LEN];
char *dir = target->dir;
void (*callback)(char *, char *) = target->callback;
int read_content = target->read_content;
free(target);
dir_strlen = strlen(dir);

struct sigaction term_handler = {.sa_handler = sig_handler};
sigaction(SIGTERM, &term_handler, NULL);

fd = inotify_init();
if (fd < 0) {
perror("inotify_init error");
exit(1);
}

struct stat st;
int err = stat(dir, &st);
if (err == -1) {
if (errno == ENOENT) {
fprintf(stderr, "Error: %s directory does not exist\n", dir);
} else {
perror("stat error");
}
exit(1);
} else {
if (!S_ISDIR(st.st_mode)) {
fprintf(stderr, "Error: %s is not a directory\n", dir);
exit(1);
}
}

if (access(dir, R_OK) != 0) {
perror("Can't access hook target directory");
exit(1);
}

uint32_t inotify_mask;
if (read_content) {
inotify_mask = IN_CLOSE_WRITE;
} else {
inotify_mask = IN_CREATE;
}

wd = inotify_add_watch(fd, dir, inotify_mask);

while (keep_watching) {
length = read(fd, buffer, EVENT_BUF_LEN);
if (length < 0) {
break;
}

i = 0;
while (i < length) {
struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
if (event->len) {
if (event->mask & inotify_mask) {
if (!(event->mask & IN_ISDIR)) { // file
int path_len = dir_strlen + strlen(event->name) + 2;
char *path = malloc(path_len);
if (path == NULL) {
perror("malloc for file path failed");
} else {
snprintf(path, path_len, "%s/%s", dir, event->name);

if (read_content) {
// Read file contents
FILE *fp = fopen(path, "rb");
char *content = NULL;
if (fp) {
fseek(fp, 0, SEEK_END);
long content_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
content = malloc(content_len + 1);
if (content) {
fread(content, 1, content_len, fp);
content[content_len] = '\0';
} else {
perror("malloc for file content failed");
}
fclose(fp);
} else {
perror("fopen failed");
}
callback(event->name, content);
free(content);
} else {
callback(event->name, NULL);
}


// Delete that file
if (unlink(path) != 0) {
perror("unlink failed");
}
free(path);
}
}
}
}
i += EVENT_SIZE + event->len;
}
}

inotify_rm_watch(fd, wd);
close(fd);
pthread_exit(0);
}

void start_watching_hooks(pthread_t *thread, char *dir, void (*callback)(char *, char *), int read_content) {
watch_target *target = malloc(sizeof(watch_target));
target->dir = dir;
target->callback = callback;
target->read_content = read_content;
pthread_create(thread, NULL, (void * (*)(void *))watch_for_file_creation, target);
watcher_thread = thread;
}

void stop_watching_hooks() {
keep_watching = 0;
pthread_kill(*watcher_thread, SIGTERM);
}
16 changes: 16 additions & 0 deletions hooks.h
@@ -0,0 +1,16 @@
#ifndef _CLIB_HOOKS_H_
#define _CLIB_HOOKS_H_

#if defined(__cplusplus)
extern "C" {
#endif

int clear_hooks(char *dirname);
void start_watching_hooks(pthread_t *thread, char *dir, void (*callback)(char *, char *), int read_content);
void stop_watching_hooks();

#if defined(__cplusplus)
}
#endif

#endif
Empty file added hooks/empty
Empty file.

0 comments on commit 508f8e9

Please sign in to comment.