UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
import.c File Reference
#include "audio/types.h"
#include "audio/wav_reader.h"
#include "debug.h"
#include "host.h"
#include "lib_common.h"
#include "keyboard_control.h"
#include "messaging.h"
#include "module.h"
#include "playback.h"
#include "tv.h"
#include "utils/color_out.h"
#include "utils/fs.h"
#include "utils/macros.h"
#include "utils/ring_buffer.h"
#include "utils/worker.h"
#include "video.h"
#include "video_capture.h"
#include "video_export.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
Include dependency graph for import.c:

Go to the source code of this file.

Classes

struct  audio_state
 
struct  client
 
struct  import_message
 
struct  message_queue
 
struct  processed_entry
 
struct  seek_data
 
struct  tile_data
 
struct  vidcap_import_state
 
struct  video_reader_data
 

Macros

#define ALLOC_ALIGN   512
 
#define BUFFER_LEN_MAX   40
 
#define MAX_CLIENTS   16
 
#define MAX_NUMBER_WORKERS   100
 
#define MOD_NAME   "[import] "
 
#define PIPE   "/tmp/ultragrid_import.fifo"
 
#define READ_N(buf, len)
 
#define VIDCAP_IMPORT_ID   0x76FA7F6D
 

Enumerations

enum  import_message_t { SEEK , FINALIZE , PAUSE }
 
enum  seek_direction_t { IMPORT_SEEK_SET , IMPORT_SEEK_CUR }
 

Functions

static void * audio_reading_thread (void *args)
 
static void cleanup_common (struct vidcap_import_state *s)
 
static void exit_reading_threads (struct vidcap_import_state *s)
 
static int flush_processed (struct processed_entry *list)
 
static void free_entry (struct processed_entry *entry)
 
static unsigned long long get_req_bytes (struct vidcap_import_state *s)
 
static int get_tile_count (const char *directory, codec_t color_spec, char *tile_delim)
 
static void import_send_message (struct import_message *msg, struct message_queue *queue)
 
static bool init_audio (struct vidcap_import_state *s, const char *audio_filename)
 
static bool initialize_import (struct vidcap_import_state *s, char *tmp, FILE **info, unsigned int flags)
 
static void message_queue_clear (struct message_queue *queue)
 
static struct video_desc parse_video_desc_info (FILE *info, long *video_frame_count)
 
static struct import_message * pop_message (struct message_queue *queue)
 
static void process_msg (struct vidcap_import_state *state, const char *message)
 
 REGISTER_MODULE (import, &vidcap_import_info, LIBRARY_CLASS_VIDEO_CAPTURE, VIDEO_CAPTURE_ABI_VERSION)
 
static void reset_import (struct vidcap_import_state *s)
 
static long strtol_checked (const char *line, const char *prefix, long min_val, long max_val)
 
static void vidcap_import_dispose_video_frame (struct video_frame *frame)
 
static void vidcap_import_done (void *state)
 
static void vidcap_import_finish (void *state)
 
static struct video_frame * vidcap_import_grab (void *state, struct audio_frame **audio)
 
static int vidcap_import_init (struct vidcap_params *params, void **state)
 
static void vidcap_import_new_message (struct module *)
 
static void vidcap_import_probe (struct device_info **available_cards, int *count, void(**deleter)(void *))
 
static void * video_reader_callback (void *arg)
 
static void * video_reading_thread (void *args)
 

Variables

static const struct video_capture_info vidcap_import_info
 

Detailed Description

Author
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z
Todo
There is a race condition between audio and video when seeking the stream. Audio may be seeked and video not yet (or vice versa). Since those parts are independent, ther will perhaps be needed to have _getf() and seek completion mutually exclusive. Perhaps not much harmfull, seems that it could cause at most 1 frame AV-desync.

Definition in file import.c.

Macro Definition Documentation

◆ ALLOC_ALIGN

#define ALLOC_ALIGN   512

Definition at line 837 of file import.c.

Referenced by video_reader_callback().

◆ BUFFER_LEN_MAX

#define BUFFER_LEN_MAX   40

Definition at line 83 of file import.c.

Referenced by video_reading_thread().

◆ MAX_CLIENTS

#define MAX_CLIENTS   16

Definition at line 84 of file import.c.

◆ MAX_NUMBER_WORKERS

#define MAX_NUMBER_WORKERS   100

Definition at line 90 of file import.c.

Referenced by initialize_import(), and video_reading_thread().

◆ MOD_NAME

#define MOD_NAME   "[import] "

◆ PIPE

#define PIPE   "/tmp/ultragrid_import.fifo"

Definition at line 88 of file import.c.

◆ READ_N

#define READ_N ( buf,
len )
Value:
if (fread(buf, len, 1, audio_file) != 1) goto error_format;
int void size_t * len

Definition at line 209 of file import.c.

◆ VIDCAP_IMPORT_ID

#define VIDCAP_IMPORT_ID   0x76FA7F6D

Definition at line 86 of file import.c.

Enumeration Type Documentation

◆ import_message_t

Enumerator
SEEK 
FINALIZE 
PAUSE 

Definition at line 105 of file import.c.

105 {
106 SEEK,
107 FINALIZE,
108 PAUSE
import_message_t
Definition import.c:105
@ FINALIZE
Definition import.c:107
@ PAUSE
Definition import.c:108
@ SEEK
Definition import.c:106

◆ seek_direction_t

Enumerator
IMPORT_SEEK_SET 
IMPORT_SEEK_CUR 

Definition at line 120 of file import.c.

120 {
seek_direction_t
Definition import.c:120
@ IMPORT_SEEK_CUR
Definition import.c:122
@ IMPORT_SEEK_SET
Definition import.c:121

Function Documentation

◆ audio_reading_thread()

static void * audio_reading_thread ( void * args)
static

Definition at line 761 of file import.c.

762{
763 struct vidcap_import_state *s = (struct vidcap_import_state *) args;
764
765 //while(s->audio_state.samples_read < s->audio_state.total_samples && !s->finish_threads) {
766 while(1) {
767 int max_read;
768 {
769 pthread_mutex_lock(&s->audio_state.lock);
772 && s->audio_state.message_queue.len == 0) {
773 pthread_cond_wait(&s->audio_state.worker_cv, &s->audio_state.lock);
774 }
775
776 while(s->audio_state.message_queue.len > 0) {
778 if(msg->type == FINALIZE) {
779 free(msg);
780 pthread_mutex_unlock(&s->audio_state.lock);
781 return NULL;
782 } else if (msg->type == SEEK) {
783 struct seek_data *data = (struct seek_data *) msg->data;
784 free(msg);
785 long long bytes = (s->audio_frame.sample_rate * data->offset / s->video_desc.fps) * s->audio_frame.bps * s->audio_frame.ch_count;
786 if (data->whence == IMPORT_SEEK_CUR) {
788 bytes = MAX(0, bytes);
789 }
790 int ret = wav_seek(s->audio_state.file, bytes, SEEK_SET, &s->audio_state.metadata);
791 log_msg(LOG_LEVEL_NOTICE, "Audio seek %lld bytes\n", bytes);
792 if (ret != 0) {
793 perror("wav_seek");
794 }
800 free(data);
801 }
802 }
803
804 max_read = ring_get_size(s->audio_state.data) -
806
807 pthread_mutex_unlock(&s->audio_state.lock);
808 }
809
810 char *buffer = (char *) malloc(max_read);
811
812 size_t samples = wav_read(buffer, max_read / s->audio_frame.ch_count / s->audio_frame.bps, s->audio_state.file, &s->audio_state.metadata);
813 s->audio_state.samples_read += samples;
814
815 {
816 pthread_mutex_lock(&s->audio_state.lock);
818 pthread_mutex_unlock(&s->audio_state.lock);
819 pthread_cond_signal(&s->audio_state.boss_cv);
820 }
821
822 free(buffer);
823 }
824
825 return NULL;
826}
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
static struct import_message * pop_message(struct message_queue *queue)
Definition import.c:653
#define MIN(a, b)
Definition macros.h:63
#define MAX(a, b)
Definition macros.h:65
int ring_get_size(struct ring_buffer *ring)
int ring_get_current_size(struct ring_buffer *ring)
void ring_buffer_flush(struct ring_buffer *buf)
void ring_buffer_write(struct ring_buffer *ring, const char *in, int len)
int sample_rate
Definition types.h:101
int ch_count
Definition types.h:104
int bps
Definition types.h:100
int video_frames_played
Definition import.c:150
long long int played_samples
Definition import.c:149
struct wav_metadata metadata
Definition import.c:139
pthread_cond_t worker_cv
Definition import.c:145
pthread_mutex_t lock
Definition import.c:148
ring_buffer_t * data
Definition import.c:140
struct message_queue message_queue
Definition import.c:152
FILE * file
Definition import.c:138
int total_samples
Definition import.c:141
pthread_cond_t boss_cv
Definition import.c:146
int samples_read
Definition import.c:142
size_t len
Definition import.c:133
struct audio_frame audio_frame
Definition import.c:158
struct audio_state audio_state
Definition import.c:159
struct video_desc video_desc
Definition import.c:160
double fps
Definition types.h:183
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)
Definition wav_reader.c:319
size_t wav_read(void *buffer, size_t sample_count, FILE *wav_file, struct wav_metadata *metadata)
Definition wav_reader.c:291

References vidcap_import_state::audio_frame, vidcap_import_state::audio_state, audio_state::boss_cv, audio_frame::bps, audio_frame::ch_count, audio_state::data, audio_state::file, FINALIZE, video_desc::fps, IMPORT_SEEK_CUR, message_queue::len, audio_state::lock, LOG_LEVEL_NOTICE, log_msg(), MAX, audio_state::message_queue, audio_state::metadata, MIN, seek_data::offset, audio_state::played_samples, pop_message(), ring_buffer_flush(), ring_buffer_write(), ring_get_current_size(), ring_get_size(), audio_frame::sample_rate, audio_state::samples_read, SEEK, audio_state::total_samples, vidcap_import_state::video_desc, audio_state::video_frames_played, wav_read(), wav_seek(), seek_data::whence, and audio_state::worker_cv.

Referenced by initialize_import(), and reset_import().

Here is the call graph for this function:

◆ cleanup_common()

static void cleanup_common ( struct vidcap_import_state * s)
static

Definition at line 607 of file import.c.

607 {
609
610 free(s->directory);
611
612 // audio
613 if(s->audio_state.has_audio) {
615
616 free(s->audio_frame.data);
617
618 fclose(s->audio_state.file);
619 pthread_cond_destroy(&s->audio_state.worker_cv);
620 pthread_cond_destroy(&s->audio_state.boss_cv);
621 pthread_mutex_destroy(&s->audio_state.lock);
622 }
623
624 module_done(&s->mod);
625 pthread_cond_destroy(&s->worker_cv);
626 pthread_cond_destroy(&s->boss_cv);
627 pthread_mutex_destroy(&s->lock);
628 free(s);
629}
void module_done(struct module *module_data)
Definition module.c:93
static int flush_processed(struct processed_entry *list)
Definition import.c:592
void ring_buffer_destroy(struct ring_buffer *ring)
char * data
Definition types.h:102
bool has_audio
Definition import.c:137
pthread_cond_t boss_cv
Definition import.c:168
pthread_cond_t worker_cv
Definition import.c:167
pthread_mutex_t lock
Definition import.c:166
struct module mod
Definition import.c:156
struct processed_entry *volatile head
Definition import.c:169

References vidcap_import_state::audio_frame, vidcap_import_state::audio_state, audio_state::boss_cv, vidcap_import_state::boss_cv, audio_frame::data, audio_state::data, vidcap_import_state::directory, audio_state::file, flush_processed(), audio_state::has_audio, vidcap_import_state::head, audio_state::lock, vidcap_import_state::lock, vidcap_import_state::mod, module_done(), ring_buffer_destroy(), audio_state::worker_cv, and vidcap_import_state::worker_cv.

Referenced by vidcap_import_done(), and vidcap_import_init().

Here is the call graph for this function:

◆ exit_reading_threads()

static void exit_reading_threads ( struct vidcap_import_state * s)
static

Definition at line 535 of file import.c.

536{
537 if (s->has_video) {
538 struct import_message *msg = (struct import_message *) malloc(sizeof(struct import_message));
539
540 msg->type = FINALIZE;
541 msg->data = NULL;
542 msg->data_len = 0;
543 msg->next = NULL;
544
545 pthread_mutex_lock(&s->lock);
547 pthread_mutex_unlock(&s->lock);
548 pthread_cond_signal(&s->worker_cv);
549
550 pthread_join(s->video_thread_id, NULL);
551 }
552
553 // audio
554 if(s->audio_state.has_audio) {
555 struct import_message *msg = (struct import_message *) malloc(sizeof(struct import_message));
556
557 msg->type = FINALIZE;
558 msg->data = NULL;
559 msg->data_len = 0;
560 msg->next = NULL;
561
562 {
563 pthread_mutex_lock(&s->audio_state.lock);
565 pthread_mutex_unlock(&s->audio_state.lock);
566 pthread_cond_signal(&s->audio_state.worker_cv);
567 }
568
569 pthread_join(s->audio_state.thread_id, NULL);
570 }
571}
static void import_send_message(struct import_message *msg, struct message_queue *queue)
Definition import.c:641
pthread_t thread_id
Definition import.c:143
struct message_queue message_queue
Definition import.c:164
pthread_t video_thread_id
Definition import.c:172

References vidcap_import_state::audio_state, FINALIZE, audio_state::has_audio, vidcap_import_state::has_video, import_send_message(), audio_state::lock, vidcap_import_state::lock, audio_state::message_queue, vidcap_import_state::message_queue, audio_state::thread_id, vidcap_import_state::video_thread_id, audio_state::worker_cv, and vidcap_import_state::worker_cv.

Referenced by reset_import(), and vidcap_import_finish().

Here is the call graph for this function:

◆ flush_processed()

static int flush_processed ( struct processed_entry * list)
static

Definition at line 592 of file import.c.

593{
594 int frames_deleted = 0;
595 struct processed_entry *current = list;
596
597 while(current != NULL) {
598 struct processed_entry *tmp = current;
599 current = current->next;
600 free_entry(tmp);
601 frames_deleted++;
602 }
603
604 return frames_deleted;
605}
static void free_entry(struct processed_entry *entry)
Definition import.c:573
Definition import.c:99
struct processed_entry * next
Definition import.c:100

References free_entry(), and processed_entry::next.

Referenced by cleanup_common(), and video_reading_thread().

Here is the call graph for this function:

◆ free_entry()

static void free_entry ( struct processed_entry * entry)
static

Definition at line 573 of file import.c.

574{
575 if (entry == NULL) {
576 return;
577 }
578 for (int i = 0; i < entry->count; ++i) {
579 aligned_free(entry->tiles[i].data);
580 }
581
582 free(entry);
583}
#define aligned_free
int count
Definition import.c:101
struct tile_data tiles[]
Definition import.c:102
char * data
Definition import.c:95

References aligned_free, processed_entry::count, tile_data::data, and processed_entry::tiles.

Referenced by flush_processed(), vidcap_import_dispose_video_frame(), and video_reader_callback().

◆ get_req_bytes()

static unsigned long long get_req_bytes ( struct vidcap_import_state * s)
static

Definition at line 1062 of file import.c.

1062 {
1063 long long int requested_samples = (long long int) (s->audio_state.video_frames_played + 0) *
1065 if (requested_samples <= 0) {
1066 return 0LL;
1067 }
1068 if ((s->audio_state.played_samples + requested_samples) > s->audio_state.total_samples) {
1069 requested_samples = s->audio_state.total_samples - s->audio_state.played_samples;
1070 }
1071 return requested_samples * s->audio_frame.bps * s->audio_frame.ch_count;
1072}

References vidcap_import_state::audio_frame, vidcap_import_state::audio_state, audio_frame::bps, audio_frame::ch_count, video_desc::fps, audio_state::played_samples, audio_frame::sample_rate, audio_state::total_samples, vidcap_import_state::video_desc, and audio_state::video_frames_played.

Referenced by vidcap_import_grab().

◆ get_tile_count()

static int get_tile_count ( const char * directory,
codec_t color_spec,
char * tile_delim )
static

Definition at line 337 of file import.c.

337 {
338 char name[1024];
339 snprintf(name, sizeof(name), "%s/%08d.%s", directory, 1,
340 get_codec_file_extension(color_spec));
341
342 struct stat sb;
343 if (stat(name, &sb) == 0) {
344 return 1;
345 }
346 int tile_count = 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",
351 directory, 1,
352 possible_tile_delim[d], i,
353 get_codec_file_extension(color_spec));
354 if (stat(name, &sb) == 0) {
355 tile_count++;
356 } else {
357 break;
358 }
359 }
360 if (tile_count > 0) {
361 *tile_delim = possible_tile_delim[d];
362 break;
363 }
364 }
365 if (tile_count == 0) {
366 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to open first file of "
367 "the video sequence.");
368 return 0;
369 }
370 return tile_count;
371}
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MOD_NAME
Definition import.c:91
const char * name
Definition settings.cpp:193
const char * get_codec_file_extension(codec_t codec)

References video_desc::color_spec, get_codec_file_extension(), LOG_LEVEL_ERROR, log_msg(), MOD_NAME, and name.

Referenced by initialize_import().

Here is the call graph for this function:

◆ import_send_message()

static void import_send_message ( struct import_message * msg,
struct message_queue * queue )
static

Definition at line 641 of file import.c.

642{
643 if(queue->head) {
644 queue->tail->next = msg;
645 queue->tail = msg;
646 } else {
647 queue->head = queue->tail = msg;
648 }
649
650 queue->len += 1;
651}
struct msghdr msg

References msg.

Referenced by exit_reading_threads(), and process_msg().

◆ init_audio()

static bool init_audio ( struct vidcap_import_state * s,
const char * audio_filename )
static

Definition at line 211 of file import.c.

212{
213 FILE *audio_file = fopen(audio_filename, "rb");
214 if(!audio_file) {
215 perror("Cannot open audio file");
216 return false;
217 }
218
219 int ret = read_wav_header(audio_file, &s->audio_state.metadata);
220 if (ret != WAV_HDR_PARSE_OK) {
221 log_msg(LOG_LEVEL_ERROR, "%s!\n", get_wav_error(ret));
222 goto error_format;
223 }
224
230
232 s->audio_frame.ch_count * 180);
233
235 s->audio_frame.data_len = 0;
236 s->audio_frame.data = (char *) malloc(s->audio_frame.max_size);
237
238 s->audio_state.file = audio_file;
239
240 pthread_cond_init(&s->audio_state.worker_cv, NULL);
241 pthread_cond_init(&s->audio_state.boss_cv, NULL);
242 pthread_mutex_init(&s->audio_state.lock, NULL);
243
244 return true;
245
246error_format:
247 fprintf(stderr, "Audio format file error - unknown format\n");
248 fclose(audio_file);
249 return false;
250}
struct ring_buffer * ring_buffer_init(int size)
int data_len
Definition types.h:103
int max_size
Definition types.h:105
unsigned int ch_count
Definition wav_reader.h:47
unsigned int sample_rate
Definition wav_reader.h:48
unsigned int bits_per_sample
Definition wav_reader.h:49
long long data_size
size of data, -1 if unknown
Definition wav_reader.h:54
const char * get_wav_error(int errcode)
Definition wav_reader.c:300
int read_wav_header(FILE *wav_file, struct wav_metadata *metadata)
Definition wav_reader.c:215
#define WAV_HDR_PARSE_OK
Definition wav_reader.h:57

References vidcap_import_state::audio_frame, vidcap_import_state::audio_state, wav_metadata::bits_per_sample, audio_state::boss_cv, audio_frame::bps, audio_frame::ch_count, wav_metadata::ch_count, audio_frame::data, audio_state::data, audio_frame::data_len, wav_metadata::data_size, audio_state::file, get_wav_error(), audio_state::lock, LOG_LEVEL_ERROR, log_msg(), audio_frame::max_size, audio_state::metadata, read_wav_header(), ring_buffer_init(), audio_frame::sample_rate, wav_metadata::sample_rate, audio_state::samples_read, audio_state::total_samples, WAV_HDR_PARSE_OK, and audio_state::worker_cv.

Referenced by initialize_import().

Here is the call graph for this function:

◆ initialize_import()

static bool initialize_import ( struct vidcap_import_state * s,
char * tmp,
FILE ** info,
unsigned int flags )
static

Definition at line 373 of file import.c.

373 {
374 bool disable_audio = false;
375
378 s->mod.priv_data = s;
380 module_register(&s->mod, s->parent);
381
382 s->video_reading_threads_count = 1; // default is single threaded
383
384 char *save_ptr = NULL;
385 char *suffix;
386 s->directory = strtok_r(tmp, ":", &save_ptr);
387 if (s->directory == NULL) {
388 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong directory name!\n");
389 return false;
390 }
391 s->directory = strdup(s->directory); // make a copy
392
393 while ((suffix = strtok_r(NULL, ":", &save_ptr)) != NULL) {
394 if (suffix[0] == '\\') { // MSW path
395 assert(strlen(s->directory) == 1); // c:\something -> should be 'c'
396 const size_t len = 2 + strlen(suffix) + 1;
397 char *tmp = (char *) malloc(len);
398 snprintf(tmp, len, "%c:%s", s->directory[0], suffix);
399 free(s->directory);
400 s->directory = tmp;
401 } else if (strcmp(suffix, "loop") == 0) {
402 s->loop = true;
403 } else if (strncmp(suffix, "mt_reading=",
404 strlen("mt_reading=")) == 0) {
406 strlen("mt_reading="));
407 assert(s->video_reading_threads_count <=
409 } else if (strcmp(suffix, "o_direct") == 0) {
410 s->o_direct = true;
411 } else if (strcmp(suffix, "noaudio") == 0) {
412 disable_audio = true;
413 } else if (strcmp(suffix, "opportunistic_audio") == 0) { // skip
414 } else if (strcmp(suffix, "exit_at_end") == 0) {
415 s->should_exit_at_end = true;
416 } else if (strncmp(suffix, "fps=", strlen("fps=")) == 0) {
417 s->force_fps = atof(suffix + strlen("fps="));
418 } else if (strstr(suffix, "frames=") == suffix) {
419 s->video_frame_count = strtol(strchr(suffix, '=') + 1, NULL, 10);
420 } else {
421 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unrecognized option: %s.\n",
422 suffix);
423 return false;
424 }
425 }
426
427 // strip video.info if user included in path
428 if (strstr(s->directory, "video.info") == s->directory) {
429 strcpy(s->directory, ".");
430 }
431 if (strstr(s->directory, "/video.info") != NULL) {
432 *strrchr(s->directory, '/') = '\0';
433 }
434
437
438 char filename[MAX_PATH_SIZE] = "";
439 strncpy(filename, s->directory, sizeof filename - 1);
440 strncat(filename, "/sound.wav", sizeof filename - strlen(filename) - 1);
441 if((flags & VIDCAP_FLAG_AUDIO_EMBEDDED) && !disable_audio && init_audio(s, filename)) {
442 s->audio_state.has_audio = true;
443 }
444
445 strncpy(filename, s->directory, sizeof filename - 1);
446 strncat(filename, "/video.info", sizeof filename - strlen(filename) - 1);
447 *info = fopen(filename, "r");
448 if (*info == NULL) {
449 perror(MOD_NAME "Failed to open video index file");
450 if (!s->audio_state.has_audio) {
451 if (errno == ENOENT) {
452 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Invalid directory?\n");
453 }
454 return false;
455 }
456 s->has_video = false;
457 s->video_desc.fps = 30; // used to sample audio
458 }
459
460 if (s->has_video) {
461 long frame_count = 0;
462 s->video_desc = parse_video_desc_info(*info, &frame_count);
463 if (s->video_desc.width == 0) {
464 return false;
465 }
466 s->video_frame_count = s->video_frame_count == 0 ? frame_count : MIN(s->video_frame_count, frame_count);
467
469 if (s->video_desc.tile_count == 0) {
470 return false;
471 }
472 }
473
474 // override metadata fps setting
475 if (s->force_fps > 0.0) {
476 s->video_desc.fps = s->force_fps;
477 }
478
479 if (s->audio_state.has_audio) {
480 if(pthread_create(&s->audio_state.thread_id, NULL, audio_reading_thread, (void *) s) != 0) {
481 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to create thread.\n");
482 return false;
483 }
484 }
485 if (s->has_video) {
486 if (pthread_create(&s->video_thread_id, NULL, video_reading_thread, (void *) s) != 0) {
487 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to create thread.\n");
488 return false;
489 }
490 }
491
492 gettimeofday(&s->prev_time, NULL);
493
495
496 return true;
497}
const char unsigned int flags
#define suffix(x, y)
#define MAX_PATH_SIZE
Definition fs.h:48
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
@ MODULE_CLASS_DATA
Definition module.h:86
static void * video_reading_thread(void *args)
Definition import.c:913
static struct video_desc parse_video_desc_info(FILE *info, long *video_frame_count)
Definition import.c:266
static void message_queue_clear(struct message_queue *queue)
Definition import.c:197
static void * audio_reading_thread(void *args)
Definition import.c:761
static int get_tile_count(const char *directory, codec_t color_spec, char *tile_delim)
Definition import.c:337
static bool init_audio(struct vidcap_import_state *s, const char *audio_filename)
Definition import.c:211
#define MAX_NUMBER_WORKERS
Definition import.c:90
static void vidcap_import_new_message(struct module *)
Definition import.c:669
void playback_register_keyboard_ctl(struct module *mod)
Definition playback.c:102
enum module_class cls
Definition module.h:115
void * priv_data
Definition module.h:126
notify_t new_message
if set, notifies module that new message is in queue, receiver lock is hold during the call
Definition module.h:119
bool should_exit_at_end
Definition import.c:182
struct module * parent
Definition import.c:157
int video_reading_threads_count
Definition import.c:181
struct timeval prev_time
Definition import.c:174
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
unsigned int width
width of every tile (!)
Definition types.h:179
#define VIDCAP_FLAG_AUDIO_EMBEDDED
HD-SDI embedded audio.

References audio_reading_thread(), vidcap_import_state::audio_state, module::cls, video_desc::color_spec, vidcap_import_state::directory, flags, vidcap_import_state::force_fps, video_desc::fps, get_tile_count(), audio_state::has_audio, vidcap_import_state::has_video, init_audio(), len, LOG_LEVEL_ERROR, log_msg(), vidcap_import_state::loop, MAX_NUMBER_WORKERS, MAX_PATH_SIZE, audio_state::message_queue, vidcap_import_state::message_queue, message_queue_clear(), MIN, vidcap_import_state::mod, MOD_NAME, MODULE_CLASS_DATA, module_init_default(), module_register(), module::new_message, vidcap_import_state::o_direct, vidcap_import_state::parent, parse_video_desc_info(), playback_register_keyboard_ctl(), vidcap_import_state::prev_time, module::priv_data, vidcap_import_state::should_exit_at_end, suffix, audio_state::thread_id, video_desc::tile_count, vidcap_import_state::tile_delim, VIDCAP_FLAG_AUDIO_EMBEDDED, vidcap_import_new_message(), vidcap_import_state::video_desc, vidcap_import_state::video_frame_count, video_reading_thread(), vidcap_import_state::video_reading_threads_count, vidcap_import_state::video_thread_id, and video_desc::width.

Referenced by vidcap_import_init().

Here is the call graph for this function:

◆ message_queue_clear()

static void message_queue_clear ( struct message_queue * queue)
static

Definition at line 197 of file import.c.

197 {
198 queue->head = queue->tail = NULL;
199 queue->len = 0;
200}

Referenced by initialize_import().

◆ parse_video_desc_info()

static struct video_desc parse_video_desc_info ( FILE * info,
long * video_frame_count )
static

Definition at line 266 of file import.c.

266 {
267 struct video_desc desc = { 0 };
268
269 char line[512];
270 uint32_t items_found = 0;
271 while (fgets(line, sizeof(line), info) != NULL) {
272 long val = 0;
273 if(strncmp(line, "version ", strlen("version ")) == 0) {
275 return (struct video_desc) { 0 };
276 }
277 items_found |= 1U<<0U;
278 } else if(strncmp(line, "width ", strlen("width ")) == 0) {
279 if ((val = strtol_checked(line, "width ", 0, INT_MAX)) == LONG_MIN) {
280 return (struct video_desc) { 0 };
281 }
282 desc.width = val;
283 items_found |= 1U<<1U;
284 } else if(strncmp(line, "height ", strlen("height ")) == 0) {
285 if ((val = strtol_checked(line, "height ", 0, INT_MAX)) == LONG_MIN) {
286 return (struct video_desc) { 0 };
287 }
288 desc.height = val;
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) { // including '\n'
293 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot read video FourCC tag.\n");
294 return (struct video_desc) { 0 };
295 }
296 uint32_t fourcc = 0U;
297 memcpy((void *) &fourcc, ptr, sizeof(fourcc));
300 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Requested codec not known.\n");
301 return (struct video_desc) { 0 };
302 }
303 items_found |= 1U<<3U;
304 } else if(strncmp(line, "fps ", strlen("fps ")) == 0) {
305 char *ptr = line + strlen("fps ");
306 desc.fps = strtod(ptr, NULL);
307 if(desc.fps == HUGE_VAL || desc.fps <= 0) {
308 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Invalid FPS.\n");
309 return (struct video_desc) { 0 };
310 }
311 items_found |= 1U<<4U;
312 } else if(strncmp(line, "interlacing ", strlen("interlacing ")) == 0) {
313 if ((val = strtol_checked(line, "interlacing ", 0, INTERLACING_MAX)) == LONG_MIN) {
314 return (struct video_desc) { 0 };
315 }
317 items_found |= 1U<<5U;
318 } else if(strncmp(line, "count ", strlen("count ")) == 0) {
319 if ((val = strtol_checked(line, "count ", 0, LONG_MAX)) == LONG_MIN) {
320 return (struct video_desc) { 0 };
321 };
322 *video_frame_count = val;
323 items_found |= 1U<<6U;
324 }
325 }
326
327 if(items_found != (1U << 7U) - 1U) {
328 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Failed while reading config file - some items missing.\n");
329 return (struct video_desc) { 0 };
330 }
331
332 assert((desc.color_spec != VIDEO_CODEC_NONE && desc.width != 0 && desc.height != 0 && desc.fps != 0.0 &&
333 *video_frame_count != 0));
334 return desc;
335}
int void * val
struct video_desc desc
static long strtol_checked(const char *line, const char *prefix, long min_val, long max_val)
Definition import.c:253
enum interlacing_t interlacing
Definition types.h:184
unsigned int height
height of every tile (!)
Definition types.h:180
interlacing_t
Definition types.h:163
@ INTERLACING_MAX
Definition types.h:169
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
codec_t get_codec_from_fcc(uint32_t fourcc)
#define VIDEO_EXPORT_SUMMARY_VERSION

References video_desc::color_spec, desc, video_desc::fps, get_codec_from_fcc(), video_desc::height, video_desc::interlacing, INTERLACING_MAX, LOG_LEVEL_ERROR, log_msg(), MOD_NAME, strtol_checked(), val, VIDEO_CODEC_NONE, VIDEO_EXPORT_SUMMARY_VERSION, and video_desc::width.

Referenced by initialize_import().

Here is the call graph for this function:

◆ pop_message()

static struct import_message * pop_message ( struct message_queue * queue)
static

Definition at line 653 of file import.c.

654{
655 assert(queue->len > 0);
656 struct import_message *ret;
657
658 ret = queue->head;
659 queue->head = queue->head->next;
660 if(queue->head == NULL) {
661 queue->tail = NULL;
662 }
663
664 queue->len -= 1;
665
666 return ret;
667}
struct import_message * next
Definition import.c:117

References import_message::next.

Referenced by audio_reading_thread(), and video_reading_thread().

◆ process_msg()

static void process_msg ( struct vidcap_import_state * state,
const char * message )
static

Definition at line 677 of file import.c.

678{
679 if(strcasecmp(message, "pause") == 0) {
680 struct import_message *msg = (struct import_message *) malloc(sizeof(struct import_message));
681 msg->type = PAUSE;
682 msg->data = NULL;
683 msg->data_len = 0;
684 msg->next = NULL;
685
686 pthread_mutex_lock(&s->lock);
687 import_send_message(msg, &s->message_queue);
688 pthread_mutex_unlock(&s->lock);
689 pthread_cond_signal(&s->worker_cv);
690 } else if(strncasecmp(message, "seek ", strlen("seek ")) == 0) {
691 const char *time_spec = message + strlen("seek ");
692
693 struct import_message *msg = (struct import_message *) malloc(sizeof(struct import_message));
694 struct seek_data *data = (struct seek_data *) malloc(sizeof(struct seek_data));
695 msg->type = SEEK;
696 msg->data = data;
697 msg->data_len = sizeof(struct seek_data);
698 msg->next = NULL;
699
700 if(time_spec[0] == '+' || time_spec[0] == '-') {
701 data->whence = IMPORT_SEEK_CUR;
702 if(strchr(time_spec, 's') != NULL) {
703 double val = atof(time_spec);
704 data->offset = val * s->video_desc.fps;
705 } else {
706 data->offset = atoi(time_spec);
707 }
708 } else {
709 data->whence = IMPORT_SEEK_SET;
710 if(strchr(time_spec, 's') != NULL) {
711 double val = atof(time_spec);
712 data->offset = val * s->video_desc.fps;
713 } else {
714 data->offset = atoi(time_spec);
715 }
716 }
717
718 struct import_message *audio_msg = NULL;
719
720 if(s->audio_state.has_audio) {
721 audio_msg = (struct import_message *) malloc(sizeof(struct import_message));
722 memcpy(audio_msg, msg, sizeof(struct import_message));
723
724 if(audio_msg->data) { // deep copy
725 audio_msg->data = malloc(msg->data_len);
726 memcpy(audio_msg->data, msg->data, msg->data_len);
727 }
728 }
729
730 {
731 pthread_mutex_lock(&s->lock);
732 import_send_message(msg, &s->message_queue);
733 pthread_mutex_unlock(&s->lock);
734 pthread_cond_signal(&s->worker_cv);
735 }
736
737 if (s->audio_state.has_audio) {
738 pthread_mutex_lock(&s->audio_state.lock);
739 import_send_message(audio_msg, &s->audio_state.message_queue);
740 pthread_mutex_unlock(&s->audio_state.lock);
741 pthread_cond_signal(&s->audio_state.worker_cv);
742 }
743 } else if(strcasecmp(message, "quit") == 0) {
744 exit_uv(0);
745 } else {
746 fprintf(stderr, "Warning: unknown message: \'%s\'\n", message);
747 }
748}
void exit_uv(int status)
Definition host.cpp:625
ssize_t offset
Definition import.c:127
seek_direction_t whence
Definition import.c:126

References vidcap_import_state::audio_state, video_desc::fps, audio_state::has_audio, IMPORT_SEEK_CUR, IMPORT_SEEK_SET, import_send_message(), audio_state::lock, vidcap_import_state::lock, audio_state::message_queue, vidcap_import_state::message_queue, seek_data::offset, PAUSE, SEEK, val, vidcap_import_state::video_desc, seek_data::whence, audio_state::worker_cv, and vidcap_import_state::worker_cv.

Referenced by vidcap_import_new_message().

Here is the call graph for this function:

◆ REGISTER_MODULE()

REGISTER_MODULE ( import ,
& vidcap_import_info,
LIBRARY_CLASS_VIDEO_CAPTURE ,
VIDEO_CAPTURE_ABI_VERSION  )

◆ reset_import()

static void reset_import ( struct vidcap_import_state * s)
static
Todo
This stuff is very ugly, rewrite it
Todo
what to do here

Definition at line 1023 of file import.c.

1024{
1026
1027 s->finished = false;
1028
1029 // clear audio state
1032 if (s->audio_state.has_audio) {
1036 if (wav_seek(s->audio_state.file, 0L, SEEK_SET, &s->audio_state.metadata) != 0) {
1037 perror("wav_seek");
1038 }
1040 }
1041
1042 if (s->has_video) {
1043 if (pthread_create(&s->video_thread_id, NULL, video_reading_thread, (void *) s) != 0) {
1044 fprintf(stderr, "Unable to create thread.\n");
1046 abort();
1047 }
1048 }
1049 if (s->audio_state.has_audio) {
1050 if(pthread_create(&s->audio_state.thread_id, NULL, audio_reading_thread, (void *) s) != 0) {
1051 fprintf(stderr, "Unable to create thread.\n");
1052 abort();
1053 }
1054 }
1055}
static void exit_reading_threads(struct vidcap_import_state *s)
Definition import.c:535

References audio_reading_thread(), vidcap_import_state::audio_state, audio_state::data, exit_reading_threads(), audio_state::file, vidcap_import_state::finished, audio_state::has_audio, vidcap_import_state::has_video, audio_state::metadata, audio_state::played_samples, ring_buffer_flush(), audio_state::samples_read, audio_state::thread_id, audio_state::video_frames_played, video_reading_thread(), vidcap_import_state::video_thread_id, and wav_seek().

Referenced by vidcap_import_grab().

Here is the call graph for this function:

◆ strtol_checked()

static long strtol_checked ( const char * line,
const char * prefix,
long min_val,
long max_val )
static
Parameters
prefixoption name including " " (eg. "width ")

Definition at line 253 of file import.c.

253 {
254 long int val = strtol(line + strlen(prefix), NULL, 10);
255 if (val == LONG_MIN || val == LONG_MAX) {
256 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot read %sline.\n", prefix);
257 return LONG_MIN;
258 }
259 if (val < min_val || val > max_val) {
260 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%sout of range [%ld..%ld]\n", prefix, min_val, max_val);
261 return LONG_MIN;
262 }
263 return val;
264}

References LOG_LEVEL_ERROR, log_msg(), MOD_NAME, and val.

Referenced by parse_video_desc_info().

Here is the call graph for this function:

◆ vidcap_import_dispose_video_frame()

static void vidcap_import_dispose_video_frame ( struct video_frame * frame)
static

Definition at line 1057 of file import.c.

1057 {
1059 vf_free(frame);
1060}
struct video_frame * frame
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame_callbacks callbacks
Definition types.h:324

References video_frame::callbacks, video_frame_callbacks::dispose_udata, frame, free_entry(), and vf_free().

Referenced by vidcap_import_grab().

Here is the call graph for this function:

◆ vidcap_import_done()

static void vidcap_import_done ( void * state)
static

Definition at line 631 of file import.c.

632{
633 struct vidcap_import_state *s = (struct vidcap_import_state *) state;
634 assert(s != NULL);
635
637
639}
void ** state
static void cleanup_common(struct vidcap_import_state *s)
Definition import.c:607
static void vidcap_import_finish(void *state)
Definition import.c:585

References cleanup_common(), state, and vidcap_import_finish().

Here is the call graph for this function:

◆ vidcap_import_finish()

static void vidcap_import_finish ( void * state)
static

Definition at line 585 of file import.c.

586{
587 struct vidcap_import_state *s = (struct vidcap_import_state *) state;
588
590}

References exit_reading_threads(), and state.

Referenced by vidcap_import_done().

Here is the call graph for this function:

◆ vidcap_import_grab()

static struct video_frame * vidcap_import_grab ( void * state,
struct audio_frame ** audio )
static

Definition at line 1075 of file import.c.

1076{
1077 struct vidcap_import_state *s = (struct vidcap_import_state *) state;
1078 struct timeval cur_time;
1079 struct video_frame *ret = NULL;
1080
1081 struct processed_entry *current = NULL;
1082
1083 if (s->has_video) {
1084 pthread_mutex_lock(&s->lock);
1085 if(s->queue_len == 0) {
1086 if (s->finished == true && s->loop) {
1087 pthread_mutex_unlock(&s->lock);
1088 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Rewinding the sequence.\n");
1089 reset_import(s);
1090 pthread_mutex_lock(&s->lock);
1091 }
1092 if (s->finished == true && s->should_exit_at_end == true) {
1093 exit_uv(0);
1094 }
1095 struct timespec ts;
1098 pthread_cond_timedwait(&s->boss_cv, &s->lock, &ts);
1099 }
1100
1101 if(s->queue_len == 0) {
1102 pthread_mutex_unlock(&s->lock);
1103 return NULL;
1104 }
1105
1106 current = s->head;
1107 assert(current != NULL);
1108
1109 s->head = s->head->next;
1110 s->queue_len -= 1;
1111
1112 pthread_mutex_unlock(&s->lock);
1113 pthread_cond_signal(&s->worker_cv);
1114
1115 ret = vf_alloc_desc(s->video_desc);
1117 ret->callbacks.dispose_udata = current;
1118 for (unsigned int i = 0; i < s->video_desc.tile_count; ++i) {
1119 ret->tiles[i].data_len =
1120 current->tiles[i].data_len;
1121 ret->tiles[i].data = current->tiles[i].data;
1122 }
1123 }
1124
1125 // audio
1126 if(s->audio_state.has_audio) {
1127 pthread_mutex_lock(&s->audio_state.lock);
1128 unsigned long long int requested_bytes = MIN(get_req_bytes(s), (unsigned long long) s->audio_frame.max_size);
1129 while(ring_get_current_size(s->audio_state.data) < (int) requested_bytes) {
1130 pthread_cond_wait(&s->audio_state.boss_cv, &s->audio_state.lock);
1131 requested_bytes = MIN(get_req_bytes(s), (unsigned long long) s->audio_frame.max_size);
1132 }
1133
1134 int ret = ring_buffer_read(s->audio_state.data, s->audio_frame.data, requested_bytes);
1135 s->audio_frame.data_len = ret;
1137 *audio = &s->audio_frame;
1139 pthread_mutex_unlock(&s->audio_state.lock);
1140 pthread_cond_signal(&s->audio_state.worker_cv);
1141 } else {
1142 *audio = NULL;
1143 }
1144
1145 gettimeofday(&cur_time, NULL);
1146 while(tv_diff_usec(cur_time, s->prev_time) < 1000000.0 / s->video_desc.fps) {
1147 gettimeofday(&cur_time, NULL);
1148 }
1149 //tv_add_usec(&s->prev_time, 1000000.0 / s->frame->fps);
1150 s->prev_time = cur_time;
1151
1152 return ret;
1153}
struct audio_frame ** audio
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
static void vidcap_import_dispose_video_frame(struct video_frame *frame)
Definition import.c:1057
static unsigned long long get_req_bytes(struct vidcap_import_state *s)
Definition import.c:1062
static void reset_import(struct vidcap_import_state *s)
Definition import.c:1023
int ring_buffer_read(struct ring_buffer *ring, char *out, int max_len)
int data_len
Definition import.c:96
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
volatile int queue_len
Definition import.c:170
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
uint32_t ts
Definition tfrc.c:101
uint32_t tv_diff_usec(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:109
void ts_add_nsec(struct timespec *ts, long long offset)
Definition tv.c:79
int timespec_get(struct timespec *ts, int base)
Definition tv.c:236
#define NS_IN_SEC
Definition tv.h:92
#define TIME_UTC
Definition tv.h:116

References audio, vidcap_import_state::audio_frame, vidcap_import_state::audio_state, audio_state::boss_cv, vidcap_import_state::boss_cv, audio_frame::bps, video_frame::callbacks, audio_frame::ch_count, audio_frame::data, audio_state::data, tile::data, tile_data::data, audio_frame::data_len, tile::data_len, tile_data::data_len, video_frame_callbacks::dispose, video_frame_callbacks::dispose_udata, exit_uv(), vidcap_import_state::finished, video_desc::fps, get_req_bytes(), audio_state::has_audio, vidcap_import_state::has_video, vidcap_import_state::head, audio_state::lock, vidcap_import_state::lock, LOG_LEVEL_NOTICE, log_msg(), vidcap_import_state::loop, audio_frame::max_size, MIN, MOD_NAME, processed_entry::next, NS_IN_SEC, audio_state::played_samples, vidcap_import_state::prev_time, vidcap_import_state::queue_len, reset_import(), ring_buffer_read(), ring_get_current_size(), vidcap_import_state::should_exit_at_end, state, video_desc::tile_count, processed_entry::tiles, video_frame::tiles, TIME_UTC, timespec_get(), ts, ts_add_nsec(), tv_diff_usec(), vf_alloc_desc(), vidcap_import_dispose_video_frame(), vidcap_import_state::video_desc, audio_state::video_frames_played, audio_state::worker_cv, and vidcap_import_state::worker_cv.

Here is the call graph for this function:

◆ vidcap_import_init()

static int vidcap_import_init ( struct vidcap_params * params,
void ** state )
static

Definition at line 500 of file import.c.

501{
502 char *tmp = strdup(vidcap_params_get_fmt(params));
503 if (strlen(tmp) == 0 || strcmp(tmp, "help") == 0) {
504 color_printf("Import usage:\n"
505 TERM_BOLD TERM_FG_RED "\t<directory>" TERM_FG_RESET "{:loop|:mt_reading=<nr_threads>|:o_direct|:exit_at_end|:fps=<fps>|frames=<n>|:disable_audio}\n" TERM_RESET
506 "where\n"
507 TERM_BOLD "\t<fps>" TERM_RESET " - overrides FPS from sequence metadata\n"
508 TERM_BOLD "\t<n> " TERM_RESET " - use only N first frames fron sequence (if less than available frames)\n");
509 free(tmp);
510 return VIDCAP_INIT_NOERR;
511 }
512
513 FILE *info = NULL; // metadata file
514 struct vidcap_import_state *s = (struct vidcap_import_state *) calloc(1, sizeof *s);
515 pthread_cond_init(&s->worker_cv, NULL);
516 pthread_cond_init(&s->boss_cv, NULL);
517 pthread_mutex_init(&s->lock, NULL);
519 s->has_video = true;
520
521 printf("vidcap_import_init\n");
522 bool init_success = initialize_import(s, tmp, &info, vidcap_params_get_flags(params));
523 free(tmp);
524 if (info != NULL) {
525 fclose(info);
526 }
527 if (init_success) {
528 *state = s;
529 return VIDCAP_INIT_OK;
530 }
532 return VIDCAP_INIT_FAIL;
533}
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_RESET
Definition color_out.h:47
#define TERM_FG_RESET
Definition color_out.h:59
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_INIT_FAIL
error ocured
static bool initialize_import(struct vidcap_import_state *s, char *tmp, FILE **info, unsigned int flags)
Definition import.c:373
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)

References vidcap_import_state::boss_cv, cleanup_common(), color_printf(), vidcap_import_state::has_video, initialize_import(), vidcap_import_state::lock, vidcap_import_state::parent, state, TERM_BOLD, TERM_FG_RED, TERM_FG_RESET, TERM_RESET, VIDCAP_INIT_FAIL, VIDCAP_INIT_NOERR, VIDCAP_INIT_OK, vidcap_params_get_flags(), vidcap_params_get_fmt(), vidcap_params_get_parent(), and vidcap_import_state::worker_cv.

Here is the call graph for this function:

◆ vidcap_import_new_message()

static void vidcap_import_new_message ( struct module * mod)
static

Definition at line 669 of file import.c.

669 {
670 struct msg_universal *m;
671 while ((m = (struct msg_universal *) check_message(mod))) {
672 process_msg((struct vidcap_import_state *) mod->priv_data, m->text);
673 free_message((struct message *) m, new_response(RESPONSE_ACCEPTED, "import is processing the request"));
674 }
675}
static void process_msg(struct vidcap_import_state *state, const char *message)
Definition import.c:677
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
Definition messaging.h:58
struct message m
Definition messaging.h:156

References check_message(), free_message(), msg_universal::m, new_response(), module::priv_data, process_msg(), and RESPONSE_ACCEPTED.

Referenced by initialize_import().

Here is the call graph for this function:

◆ vidcap_import_probe()

static void vidcap_import_probe ( struct device_info ** available_cards,
int * count,
void(** deleter )(void *) )
static

Definition at line 202 of file import.c.

203{
204 *deleter = free;
205 *available_cards = NULL;
206 *count = 0;
207}
int void(** deleter)(void *))
int count
Definition hd-rum.c:44

References count, and deleter.

◆ video_reader_callback()

static void * video_reader_callback ( void * arg)
static

Definition at line 839 of file import.c.

840{
841 struct video_reader_data *data =
842 (struct video_reader_data *) arg;
843
844 data->entry = (struct processed_entry *) calloc(1, sizeof(struct processed_entry) + data->tile_count * sizeof(struct tile_data));
845 assert(data->entry != NULL);
846 data->entry->next = NULL;
847 data->entry->count = data->tile_count;
848
849 for (unsigned int i = 0; i < data->tile_count; i++) {
850 char name[1048];
851 char tile_idx[3] = "";
852 if (data->tile_count > 1) {
853 snprintf(tile_idx, sizeof tile_idx, "%c%d", data->tile_delim, i);
854 }
855 snprintf(name, sizeof(name), "%s%s.%s",
856 data->file_name_prefix, tile_idx,
857 data->file_name_suffix);
858
859 struct stat sb;
860
861 int flags = O_RDONLY;
862#ifdef _WIN32
863 flags |= O_BINARY;
864#endif
865 if (data->o_direct) {
866#ifdef __linux__
867 flags |= O_DIRECT;
868#endif
869 }
870 int fd = open(name, flags);
871 if(fd == -1) {
872 perror("open");
873 return NULL;
874 }
875 if (fstat(fd, &sb)) {
876 perror("fstat");
877 close(fd);
878 free_entry(data->entry);
879 return NULL;
880 }
881
882 data->entry->tiles[i].data_len = sb.st_size;
883 const int aligned_data_len = (data->entry->tiles[i].data_len + ALLOC_ALIGN - 1)
885 // alignment needed when using O_DIRECT flag
886 data->entry->tiles[i].data = (char *)
887 aligned_malloc(aligned_data_len, ALLOC_ALIGN);
888 assert(data->entry->tiles[i].data != NULL);
889
890 ssize_t bytes = 0;
891 do {
892 ssize_t res = read(fd, data->entry->tiles[i].data + bytes,
893 (data->entry->tiles[i].data_len - bytes + ALLOC_ALIGN - 1)
895 if (res <= 0) {
896 perror("read");
897 for (unsigned int i = 0; i < data->tile_count; i++) {
898 aligned_free(data->entry->tiles[i].data);
899 }
900 free(data->entry);
901 close(fd);
902 return NULL;
903 }
904 bytes += res;
905 } while (bytes < data->entry->tiles[i].data_len);
906
907 close(fd);
908 }
909
910 return data;
911}
#define ALLOC_ALIGN
Definition import.c:837
static void * aligned_malloc(size_t size, size_t alignment)
char file_name_prefix[512]
Definition import.c:829
struct processed_entry * entry
Definition import.c:833
unsigned int tile_count
Definition import.c:832
char file_name_suffix[512]
Definition import.c:830

References aligned_free, aligned_malloc(), ALLOC_ALIGN, processed_entry::count, tile_data::data, tile_data::data_len, video_reader_data::entry, video_reader_data::file_name_prefix, video_reader_data::file_name_suffix, flags, free_entry(), name, processed_entry::next, video_reader_data::o_direct, video_reader_data::tile_count, video_reader_data::tile_delim, and processed_entry::tiles.

Referenced by video_reading_thread().

Here is the call graph for this function:

◆ video_reading_thread()

static void * video_reading_thread ( void * args)
static

while(index < s->video_frame_count && !s->finish_threads) {

Todo
are these checks necessary?

Definition at line 913 of file import.c.

914{
915 struct vidcap_import_state *s = (struct vidcap_import_state *) args;
916 long index = 0;
917
918 bool paused = false;
919
921 while(1) {
922 {
923 pthread_mutex_lock(&s->lock);
924 while((s->queue_len >= BUFFER_LEN_MAX - 1 || index >= s->video_frame_count || paused)
925 && s->message_queue.len == 0) {
926 if (index >= s->video_frame_count) {
927 s->finished = true;
928 }
929 pthread_cond_wait(&s->worker_cv, &s->lock);
930 }
931
932 while(s->message_queue.len > 0) {
934 if(msg->type == FINALIZE) {
935 free(msg);
936 pthread_mutex_unlock(&s->lock);
937 return NULL;
938 } else if(msg->type == PAUSE) {
939 paused = !paused;
940 printf("Toggle pause\n");
941
942 index -= flush_processed(s->head);
943 s->queue_len = 0;
944 s->head = s->tail = NULL;
945
946 free(msg);
947 } else if (msg->type == SEEK) {
949 s->queue_len = 0;
950 s->head = s->tail = NULL;
951
952 struct seek_data *data = (struct seek_data *) msg->data;
953 free(msg);
954 if(data->whence == IMPORT_SEEK_CUR) {
955 index += data->offset;
956 } else if (data->whence == IMPORT_SEEK_SET) {
957 index = data->offset;
958 }
959 index = MIN(MAX(0L, index), s->video_frame_count - 1);
960 printf("Current index: frame %ld\n", index);
961 free(data);
962 } else {
963 fprintf(stderr, "Unknown message type: %d!\n", msg->type);
964 abort();
965 }
966 }
967 pthread_mutex_unlock(&s->lock);
968 }
969
971 index = MIN(MAX(0L, index), s->video_frame_count - 1);
972
973 struct video_reader_data data_reader[MAX_NUMBER_WORKERS];
975
976 int number_workers = s->video_reading_threads_count;
977 if (index + number_workers >= s->video_frame_count) {
978 number_workers = s->video_frame_count - index;
979 }
980 // run workers
981 for (int i = 0; i < number_workers; ++i) {
982 struct video_reader_data *data =
983 &data_reader[i];
984 data->o_direct = s->o_direct;
986 data->tile_delim = s->tile_delim;
987 snprintf(data->file_name_prefix, sizeof(data->file_name_prefix),
988 "%s/%08ld", s->directory, index + i + 1);
989 strncpy(data->file_name_suffix,
991 sizeof(data->file_name_suffix));
992 data->entry = NULL;
993 task_handle[i] = task_run_async(video_reader_callback, data);
994 }
995
996 // wait for workers to finish
997 for (int i = 0; i < number_workers; ++i) {
998 struct video_reader_data *data =
999 (struct video_reader_data *)
1000 wait_task(task_handle[i]);
1001 if (!data || data->entry == NULL)
1002 continue;
1003 {
1004 pthread_mutex_lock(&s->lock);
1005 if(s->head) {
1006 s->tail->next = data->entry;
1007 s->tail = data->entry;
1008 } else {
1009 s->head = s->tail = data->entry;
1010 }
1011 s->queue_len += 1;
1012
1013 pthread_mutex_unlock(&s->lock);
1014 pthread_cond_signal(&s->boss_cv);
1015 }
1016 }
1017 index += number_workers;
1018 }
1019
1020 return NULL;
1021}
static void * video_reader_callback(void *arg)
Definition import.c:839
#define BUFFER_LEN_MAX
Definition import.c:83
struct processed_entry *volatile *volatile tail
Definition import.c:169
void * wait_task(task_result_handle_t handle)
Definition worker.cpp:280
task_result_handle_t task_run_async(runnable_t task, void *data)
Runs task asynchronously.
Definition worker.cpp:262
void * task_result_handle_t
Definition worker.h:49

References vidcap_import_state::boss_cv, BUFFER_LEN_MAX, video_desc::color_spec, vidcap_import_state::directory, video_reader_data::entry, video_reader_data::file_name_prefix, video_reader_data::file_name_suffix, FINALIZE, vidcap_import_state::finished, flush_processed(), get_codec_file_extension(), vidcap_import_state::head, IMPORT_SEEK_CUR, IMPORT_SEEK_SET, message_queue::len, vidcap_import_state::lock, MAX, MAX_NUMBER_WORKERS, vidcap_import_state::message_queue, MIN, processed_entry::next, vidcap_import_state::o_direct, video_reader_data::o_direct, seek_data::offset, PAUSE, pop_message(), vidcap_import_state::queue_len, SEEK, vidcap_import_state::tail, task_run_async(), video_desc::tile_count, video_reader_data::tile_count, vidcap_import_state::tile_delim, video_reader_data::tile_delim, vidcap_import_state::video_desc, vidcap_import_state::video_frame_count, video_reader_callback(), vidcap_import_state::video_reading_threads_count, wait_task(), seek_data::whence, and vidcap_import_state::worker_cv.

Referenced by initialize_import(), and reset_import().

Here is the call graph for this function:

Variable Documentation

◆ vidcap_import_info

const struct video_capture_info vidcap_import_info
static
Initial value:
= {
}
static struct video_frame * vidcap_import_grab(void *state, struct audio_frame **audio)
Definition import.c:1075
static int vidcap_import_init(struct vidcap_params *params, void **state)
Definition import.c:500
static void vidcap_import_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
Definition import.c:202
static void vidcap_import_done(void *state)
Definition import.c:631

Definition at line 1155 of file import.c.