Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
3,904 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.
Oops, something went wrong.