83#define BUFFER_LEN_MAX 40
86#define VIDCAP_IMPORT_ID 0x76FA7F6D
88#define PIPE "/tmp/ultragrid_import.fifo"
90#define MAX_NUMBER_WORKERS 100
91#define MOD_NAME "[import] "
198 queue->head = queue->tail = NULL;
205 *available_cards = NULL;
209#define READ_N(buf, len) if (fread(buf, len, 1, audio_file) != 1) goto error_format;
213 FILE *audio_file = fopen(audio_filename,
"rb");
215 perror(
"Cannot open audio file");
247 fprintf(stderr,
"Audio format file error - unknown format\n");
253static long strtol_checked(
const char *line,
const char *prefix,
long min_val,
long max_val) {
254 long int val = strtol(line + strlen(prefix), NULL, 10);
255 if (
val == LONG_MIN ||
val == LONG_MAX) {
270 uint32_t items_found = 0;
271 while (fgets(line,
sizeof(line), info) != NULL) {
273 if(strncmp(line,
"version ", strlen(
"version ")) == 0) {
277 items_found |= 1U<<0U;
278 }
else if(strncmp(line,
"width ", strlen(
"width ")) == 0) {
283 items_found |= 1U<<1U;
284 }
else if(strncmp(line,
"height ", strlen(
"height ")) == 0) {
289 items_found |= 1U<<2U;
290 }
else if(strncmp(line,
"fourcc ", strlen(
"fourcc ")) == 0) {
291 char *ptr = line + strlen(
"fourcc ");
292 if(strlen(ptr) != 5) {
296 uint32_t fourcc = 0U;
297 memcpy((
void *) &fourcc, ptr,
sizeof(fourcc));
303 items_found |= 1U<<3U;
304 }
else if(strncmp(line,
"fps ", strlen(
"fps ")) == 0) {
305 char *ptr = line + strlen(
"fps ");
311 items_found |= 1U<<4U;
312 }
else if(strncmp(line,
"interlacing ", strlen(
"interlacing ")) == 0) {
317 items_found |= 1U<<5U;
318 }
else if(strncmp(line,
"count ", strlen(
"count ")) == 0) {
322 *video_frame_count =
val;
323 items_found |= 1U<<6U;
327 if(items_found != (1U << 7U) - 1U) {
333 *video_frame_count != 0));
339 snprintf(
name,
sizeof(
name),
"%s/%08d.%s", directory, 1,
343 if (stat(
name, &sb) == 0) {
347 char possible_tile_delim[] = {
'_',
'-' };
348 for (
unsigned int d = 0; d <
sizeof possible_tile_delim; d++) {
349 for (
int i = 0; i < 10; i++) {
350 snprintf(
name,
sizeof(
name),
"%s/%08d%c%d.%s",
352 possible_tile_delim[d], i,
354 if (stat(
name, &sb) == 0) {
360 if (tile_count > 0) {
361 *tile_delim = possible_tile_delim[d];
365 if (tile_count == 0) {
367 "the video sequence.");
374 bool disable_audio =
false;
384 char *save_ptr = NULL;
386 s->
directory = strtok_r(tmp,
":", &save_ptr);
393 while ((
suffix = strtok_r(NULL,
":", &save_ptr)) != NULL) {
396 const size_t len = 2 + strlen(
suffix) + 1;
397 char *tmp = (
char *) malloc(
len);
401 }
else if (strcmp(
suffix,
"loop") == 0) {
403 }
else if (strncmp(
suffix,
"mt_reading=",
404 strlen(
"mt_reading=")) == 0) {
406 strlen(
"mt_reading="));
409 }
else if (strcmp(
suffix,
"o_direct") == 0) {
411 }
else if (strcmp(
suffix,
"noaudio") == 0) {
412 disable_audio =
true;
413 }
else if (strcmp(
suffix,
"opportunistic_audio") == 0) {
414 }
else if (strcmp(
suffix,
"exit_at_end") == 0) {
416 }
else if (strncmp(
suffix,
"fps=", strlen(
"fps=")) == 0) {
431 if (strstr(s->
directory,
"/video.info") != NULL) {
439 strncpy(filename, s->
directory,
sizeof filename - 1);
440 strncat(filename,
"/sound.wav",
sizeof filename - strlen(filename) - 1);
445 strncpy(filename, s->
directory,
sizeof filename - 1);
446 strncat(filename,
"/video.info",
sizeof filename - strlen(filename) - 1);
447 *info = fopen(filename,
"r");
449 perror(
MOD_NAME "Failed to open video index file");
451 if (errno == ENOENT) {
461 long frame_count = 0;
503 if (strlen(tmp) == 0 || strcmp(tmp,
"help") == 0) {
508 TERM_BOLD "\t<n> " TERM_RESET " - use only N first frames fron sequence (if less than available frames)\n");
516 pthread_cond_init(&s->
boss_cv, NULL);
517 pthread_mutex_init(&s->
lock, NULL);
521 printf(
"vidcap_import_init\n");
545 pthread_mutex_lock(&s->
lock);
547 pthread_mutex_unlock(&s->
lock);
578 for (
int i = 0; i < entry->
count; ++i) {
594 int frames_deleted = 0;
597 while(current != NULL) {
599 current = current->
next;
604 return frames_deleted;
626 pthread_cond_destroy(&s->
boss_cv);
627 pthread_mutex_destroy(&s->
lock);
644 queue->tail->next =
msg;
647 queue->head = queue->tail =
msg;
655 assert(queue->len > 0);
659 queue->head = queue->head->
next;
660 if(queue->head == NULL) {
679 if(strcasecmp(
message,
"pause") == 0) {
686 pthread_mutex_lock(&s->
lock);
688 pthread_mutex_unlock(&s->
lock);
690 }
else if(strncasecmp(
message,
"seek ", strlen(
"seek ")) == 0) {
691 const char *time_spec =
message + strlen(
"seek ");
700 if(time_spec[0] ==
'+' || time_spec[0] ==
'-') {
702 if(strchr(time_spec,
's') != NULL) {
703 double val = atof(time_spec);
706 data->
offset = atoi(time_spec);
710 if(strchr(time_spec,
's') != NULL) {
711 double val = atof(time_spec);
714 data->
offset = atoi(time_spec);
721 audio_msg = (struct import_message *) malloc(sizeof(struct import_message));
722 memcpy(audio_msg, msg, sizeof(struct import_message));
724 if(audio_msg->data) {
725 audio_msg->data = malloc(msg->data_len);
726 memcpy(audio_msg->data, msg->data, msg->data_len);
731 pthread_mutex_lock(&s->
lock);
733 pthread_mutex_unlock(&s->
lock);
743 }
else if(strcasecmp(
message,
"quit") == 0) {
746 fprintf(stderr,
"Warning: unknown message: \'%s\'\n",
message);
782 }
else if (
msg->type ==
SEEK) {
788 bytes =
MAX(0, bytes);
810 char *buffer = (
char *) malloc(max_read);
837#define ALLOC_ALIGN 512
845 assert(data->
entry != NULL);
849 for (
unsigned int i = 0; i < data->
tile_count; i++) {
851 char tile_idx[3] =
"";
853 snprintf(tile_idx,
sizeof tile_idx,
"%c%d", data->
tile_delim, i);
855 snprintf(
name,
sizeof(
name),
"%s%s.%s",
861 int flags = O_RDONLY;
875 if (fstat(fd, &sb)) {
897 for (
unsigned int i = 0; i < data->
tile_count; i++) {
905 }
while (bytes < data->entry->tiles[i].data_len);
923 pthread_mutex_lock(&s->
lock);
936 pthread_mutex_unlock(&s->
lock);
940 printf(
"Toggle pause\n");
947 }
else if (
msg->type ==
SEEK) {
960 printf(
"Current index: frame %ld\n", index);
963 fprintf(stderr,
"Unknown message type: %d!\n",
msg->type);
967 pthread_mutex_unlock(&s->
lock);
981 for (
int i = 0; i < number_workers; ++i) {
988 "%s/%08ld", s->
directory, index + i + 1);
997 for (
int i = 0; i < number_workers; ++i) {
1001 if (!data || data->
entry == NULL)
1004 pthread_mutex_lock(&s->
lock);
1013 pthread_mutex_unlock(&s->
lock);
1014 pthread_cond_signal(&s->
boss_cv);
1017 index += number_workers;
1044 fprintf(stderr,
"Unable to create thread.\n");
1051 fprintf(stderr,
"Unable to create thread.\n");
1065 if (requested_samples <= 0) {
1078 struct timeval cur_time;
1084 pthread_mutex_lock(&s->
lock);
1087 pthread_mutex_unlock(&s->
lock);
1090 pthread_mutex_lock(&s->
lock);
1102 pthread_mutex_unlock(&s->
lock);
1107 assert(current != NULL);
1112 pthread_mutex_unlock(&s->
lock);
1145 gettimeofday(&cur_time, NULL);
1147 gettimeofday(&cur_time, NULL);
struct video_frame * frame
const char unsigned int flags
struct audio_frame ** audio
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
This file contains definition of some common audio types.
int color_printf(const char *format,...)
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_NOTICE
information that may be interesting
#define LOG_LEVEL_ERROR
general errors
void module_init_default(struct module *module_data)
void module_register(struct module *module_data, struct module *parent)
void module_done(struct module *module_data)
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
static long strtol_checked(const char *line, const char *prefix, long min_val, long max_val)
static void * video_reading_thread(void *args)
static void import_send_message(struct import_message *msg, struct message_queue *queue)
static void * video_reader_callback(void *arg)
static struct video_desc parse_video_desc_info(FILE *info, long *video_frame_count)
static void cleanup_common(struct vidcap_import_state *s)
static const struct video_capture_info vidcap_import_info
static void process_msg(struct vidcap_import_state *state, const char *message)
static void vidcap_import_dispose_video_frame(struct video_frame *frame)
static bool initialize_import(struct vidcap_import_state *s, char *tmp, FILE **info, unsigned int flags)
static int flush_processed(struct processed_entry *list)
static void free_entry(struct processed_entry *entry)
static struct video_frame * vidcap_import_grab(void *state, struct audio_frame **audio)
static void message_queue_clear(struct message_queue *queue)
static void exit_reading_threads(struct vidcap_import_state *s)
static void * audio_reading_thread(void *args)
static struct import_message * pop_message(struct message_queue *queue)
static int vidcap_import_init(struct vidcap_params *params, void **state)
static unsigned long long get_req_bytes(struct vidcap_import_state *s)
static void vidcap_import_finish(void *state)
static void vidcap_import_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
static int get_tile_count(const char *directory, codec_t color_spec, char *tile_delim)
static bool init_audio(struct vidcap_import_state *s, const char *audio_filename)
static void vidcap_import_done(void *state)
static void reset_import(struct vidcap_import_state *s)
#define MAX_NUMBER_WORKERS
static void vidcap_import_new_message(struct module *)
static void * aligned_malloc(size_t size, size_t alignment)
@ LIBRARY_CLASS_VIDEO_CAPTURE
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct message * check_message(struct module *mod)
#define RESPONSE_ACCEPTED
void playback_register_keyboard_ctl(struct module *mod)
int ring_get_size(struct ring_buffer *ring)
int ring_get_current_size(struct ring_buffer *ring)
void ring_buffer_destroy(struct ring_buffer *ring)
struct ring_buffer * ring_buffer_init(int size)
void ring_buffer_flush(struct ring_buffer *buf)
int ring_buffer_read(struct ring_buffer *ring, char *out, int max_len)
void ring_buffer_write(struct ring_buffer *ring, const char *in, int len)
struct used to comunicate with audio capture/playback device
long long int played_samples
struct wav_metadata metadata
struct message_queue message_queue
struct import_message * next
struct import_message * tail
struct import_message * head
notify_t new_message
if set, notifies module that new message is in queue, receiver lock is hold during the call
struct processed_entry * next
char * data
Raw tile data. Pointer must be at least 4B aligned.
unsigned int data_len
length of the data
struct processed_entry *volatile *volatile tail
struct audio_frame audio_frame
struct message_queue message_queue
pthread_t video_thread_id
struct audio_state audio_state
struct video_desc video_desc
int video_reading_threads_count
struct processed_entry *volatile head
enum interlacing_t interlacing
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
void(* dispose)(struct video_frame *)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
struct video_frame_callbacks callbacks
char file_name_prefix[512]
struct processed_entry * entry
char file_name_suffix[512]
uint32_t tv_diff_usec(struct timeval curr_time, struct timeval prev_time)
void ts_add_nsec(struct timespec *ts, long long offset)
int timespec_get(struct timespec *ts, int base)
@ VIDEO_CODEC_NONE
dummy color spec
This is an umbrella header for video functions.
struct module * vidcap_params_get_parent(const struct vidcap_params *params)
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_EMBEDDED
HD-SDI embedded audio.
const char * get_codec_file_extension(codec_t codec)
codec_t get_codec_from_fcc(uint32_t fourcc)
#define VIDEO_EXPORT_SUMMARY_VERSION
int wav_seek(FILE *wav_file, long offset, int whence, struct wav_metadata *metadata)
same as fseek but WAV header presence is respected (for SEEK SET)
const char * get_wav_error(int errcode)
size_t wav_read(void *buffer, size_t sample_count, FILE *wav_file, struct wav_metadata *metadata)
int read_wav_header(FILE *wav_file, struct wav_metadata *metadata)
void * wait_task(task_result_handle_t handle)
task_result_handle_t task_run_async(runnable_t task, void *data)
Runs task asynchronously.
void * task_result_handle_t