Merge branch 'trunk' of http://seth.ics.muni.cz/git/ultragrid into I2CAT's trunk

This commit is contained in:
Gerard CL
2014-05-20 15:26:01 +02:00
42 changed files with 1228 additions and 7920 deletions

View File

@@ -8,7 +8,7 @@ LINKER = @LINKER@
COMMON_FLAGS = -g @DEFS@ -DPATH_PREFIX=@prefix@ -DLIB_DIR=@libdir@ -Wall -Wextra -Wpointer-arith -msse2
CFLAGS = @CFLAGS@ @X_CFLAGS@ $(COMMON_FLAGS) -D_GNU_SOURCE
CPPFLAGS = @CPPFLAGS@ -D_GNU_SOURCE
CXXFLAGS = @CXXFLAGS@ $(COMMON_FLAGS) -D_GNU_SOURCE
CXXFLAGS = @CXXFLAGS@ $(COMMON_FLAGS) -D_GNU_SOURCE
NVCCFLAGS = @NVCCFLAGS@
LDFLAGS = @LDFLAGS@
LIBS += @LIBS@ @JACK_TRANS_LIB@ @MATHLIBS@ @COREAUDIO_LIB@ \
@@ -125,6 +125,7 @@ OBJS = @OBJS@ \
src/video_capture/aggregate.o \
src/video_capture/import.o \
src/video_capture/null.o \
src/video_capture/switcher.o \
src/video_compress.o \
src/video_compress/none.o \
src/video_decompress.o \
@@ -157,9 +158,10 @@ REFLECTOR_OBJS = src/hd-rum-translator/hd-rum-decompress.o \
src/hd-rum-translator/hd-rum-translator.o
IMPORT_CONTROL_KEYBOARD_OBJS = src/import_control_keyboard.o
SWITCHER_CONTROL_KEYBOARD_OBJS = src/switcher_control_keyboard.o
# -------------------------------------------------------------------------------------------------
all: $(TARGET) $(GUI_TARGET) bin/import_control_keyboard $(REFLECTOR_TARGET) modules ag-plugins configure-messages
all: $(TARGET) $(GUI_TARGET) bin/import_control_keyboard bin/switcher_control_keyboard $(REFLECTOR_TARGET) modules ag-plugins configure-messages
modules: @LIB_TARGETS@
@@ -171,7 +173,10 @@ $(TARGET): bindir $(OBJS) $(ULTRAGRID_OBJS) $(GENERATED_HEADERS)
if [ -n "@DLL_LIBS@" ]; then $(INSTALL) -m 644 @DLL_LIBS@ bin; fi
bin/import_control_keyboard: bindir $(IMPORT_CONTROL_KEYBOARD_OBJS)
$(LINKER) $(LDFLAGS) $(IMPORT_CONTROL_KEYBOARD_OBJS) @IMPORT_CONTROL_KEYBOARD_LIBS@ -o $@
$(LINKER) $(LDFLAGS) $(IMPORT_CONTROL_KEYBOARD_OBJS) @NCURSES_LIBS@ -o $@
bin/switcher_control_keyboard: bindir $(SWITCHER_CONTROL_KEYBOARD_OBJS)
$(LINKER) $(LDFLAGS) $(SWITCHER_CONTROL_KEYBOARD_OBJS) @NCURSES_LIBS@ -o $@ -pthread
$(REFLECTOR_TARGET): bindir $(OBJS) $(GENERATED_HEADERS) $(REFLECTOR_OBJS)
$(LINKER) $(LDFLAGS) $(OBJS) $(REFLECTOR_OBJS) $(LIBS) -o $@

View File

@@ -2548,7 +2548,6 @@ then
SAVED_LIBS=$LIBS
LIBAVCODEC_LIBS="$LIBAVCODEC_LIBS $LIBAVUTIL_LIBS" # append libavutil
LIBS="$LIBS $LIBAVCODEC_LIBS"
AC_CHECK_FUNCS(avcodec_encode_video2)
LIBS=$SAVED_LIBS
else
LIBAVCODEC_LIBS=
@@ -2628,11 +2627,10 @@ if test $system = Linux -o $system = MacOSX; then
if test $FOUND_NCURSES = yes; then
AC_DEFINE([HAVE_NCURSES], [1], [Build with ncurses support])
IMPORT_CONTROL_KEYBOARD_LIBS="$NCURSES_LIBS"
fi
fi
AC_SUBST(IMPORT_CONTROL_KEYBOARD_LIBS)
AC_SUBST(NCURSES_LIBS)
# -------------------------------------------------------------------------------------------------
# OpenSSL-libcrypto

BIN
share/logo_cesnet.pam Normal file

Binary file not shown.

View File

@@ -144,6 +144,8 @@ struct state_audio {
int resample_to;
char *requested_encryption;
volatile bool paused;
};
/**
@@ -196,13 +198,15 @@ struct state_audio * audio_cfg_init(struct module *parent, const char *addrs, in
const char *send_cfg, const char *recv_cfg,
char *jack_cfg, const char *fec_cfg, const char *encryption,
char *audio_channel_map, const char *audio_scale,
bool echo_cancellation, bool use_ipv6, const char *mcast_if, audio_codec_t audio_codec,
int resample_to, bool isStd, long packet_rate)
bool echo_cancellation, bool use_ipv6, const char *mcast_if,
const char *audio_codec_cfg,
bool isStd, long packet_rate)
{
struct state_audio *s = NULL;
char *tmp, *unused = NULL;
UNUSED(unused);
char *addr;
int resample_to = get_audio_codec_sample_rate(audio_codec_cfg);
audio_capture_init_devices();
audio_playback_init_devices();
@@ -256,7 +260,7 @@ struct state_audio * audio_cfg_init(struct module *parent, const char *addrs, in
s->audio_sender_thread_started = s->audio_receiver_thread_started = false;
s->resample_to = resample_to;
s->audio_coder = audio_codec_init(audio_codec, AUDIO_CODER);
s->audio_coder = audio_codec_init_cfg(audio_codec_cfg, AUDIO_CODER);
if(!s->audio_coder) {
goto error;
}
@@ -514,6 +518,8 @@ static void *audio_receiver_thread(void *arg)
while (!should_exit_audio) {
bool decoded = false;
pbuf_data.buffer.data_len = 0;
if(s->receiver == NET_NATIVE) {
gettimeofday(&curr_time, NULL);
ts = tv_diff(curr_time, s->start_time) * 90000;
@@ -527,7 +533,10 @@ static void *audio_receiver_thread(void *arg)
cp = pdb_iter_init(s->audio_participants, &it);
while (cp != NULL) {
if (audio_pbuf_decode(cp->playout_buffer, curr_time, decode_audio_frame, &pbuf_data)) {
// We iterate in loop since there can be more than one frmae present in
// the playout buffer and it would be discarded by following pbuf_remove()
// call.
while (pbuf_decode(cp->playout_buffer, curr_time, decode_audio_frame, &pbuf_data)) {
decoded = true;
}
@@ -552,7 +561,8 @@ static void *audio_receiver_thread(void *arg)
cp = pdb_iter_init(s->audio_participants, &it);
while (cp != NULL) {
if (audio_pbuf_decode(cp->playout_buffer, curr_time, decode_audio_frame_mulaw, &pbuf_data)) {
// should be perhaps run iteratively? similarly to NET_NATIVE
if (pbuf_decode(cp->playout_buffer, curr_time, decode_audio_frame_mulaw, &pbuf_data)) {
bool failed = false;
if(s->echo_state) {
#ifdef HAVE_SPEEX
@@ -733,9 +743,15 @@ static void audio_sender_process_message(struct state_audio *s, struct msg_sende
&s->audio_network_parameters);
break;
case SENDER_MSG_PAUSE:
s->paused = true;
break;
case SENDER_MSG_PLAY:
s->paused = false;
break;
case SENDER_MSG_CHANGE_FEC:
fprintf(stderr, "Not implemented!\n");
abort();
}
}
@@ -770,6 +786,9 @@ static void *audio_sender_thread(void *arg)
continue;
#endif
}
if (s->paused) {
continue;
}
if(s->sender == NET_NATIVE) {
// RESAMPLE
resample(&resample_state, buffer);

View File

@@ -126,8 +126,8 @@ struct state_audio * audio_cfg_init(struct module *parent, const char *addrs, in
const char *send_cfg, const char *recv_cfg,
char *jack_cfg, const char *fec_cfg, const char *encryption,
char *audio_channel_map, const char *audio_scale,
bool echo_cancellation, bool use_ipv6, const char *mcast_iface, audio_codec_t audio_codec,
int resample_to, bool isStd, long packet_rate);
bool echo_cancellation, bool use_ipv6, const char *mcast_iface, const char *audio_codec_cfg,
bool isStd, long packet_rate);
void audio_finish(void);
void audio_done(struct state_audio *s);
void audio_join(struct state_audio *s);

View File

@@ -203,8 +203,6 @@ void * audio_cap_jack_init(char *cfg)
s->data = ring_buffer_init(s->frame.max_size);
free(ports);
if(jack_set_sample_rate_callback(s->client, jack_samplerate_changed_callback, (void *) s)) {
fprintf(stderr, "[JACK capture] Registring callback problem.\n");
goto release_client;
@@ -234,6 +232,8 @@ void * audio_cap_jack_init(char *cfg)
}
}
free(ports);
return s;
release_client:

View File

@@ -87,7 +87,7 @@ static struct audio_codec *audio_codecs[MAX_AUDIO_CODECS] = {
&dummy_pcm_audio_codec,
NULL_IF_BUILD_LIBRARIES(LIBAVCODEC_AUDIO_CODEC_HANDLE),
};
static struct audio_codec_state *audio_codec_init_real(audio_codec_t audio_codec,
static struct audio_codec_state *audio_codec_init_real(const char *audio_codec_cfg,
audio_codec_direction_t direction, bool try_init);
static void register_audio_codec_real(struct audio_codec *);
@@ -111,17 +111,20 @@ struct audio_codec_state {
audio_codec_t codec;
audio_codec_direction_t direction;
audio_frame2 *out;
int bitrate;
};
void list_audio_codecs(void) {
printf("Syntax:\n");
printf("\t--audio-codec <audio_codec>[:<sampling_rate>]\n");
printf("\t--audio-codec <audio_codec>[:sample_rate=<sampling_rate>][:bitrate=<bitrate>]\n");
printf("\n");
printf("Supported audio codecs:\n");
for(int i = 0; i < audio_codec_info_len; ++i) {
if(i != AC_NONE) {
printf("\t%s", audio_codec_info[i].name);
struct audio_codec_state *st = audio_codec_init_real(i, AUDIO_CODER, true);
struct audio_codec_state *st = (struct audio_codec_state *)
audio_codec_init_real(get_name_to_audio_codec((audio_codec_t) i),
AUDIO_CODER, true);
if(!st) {
printf(" - unavailable");
} else {
@@ -145,11 +148,19 @@ static void load_libraries(void)
struct audio_codec_state *audio_codec_init(audio_codec_t audio_codec,
audio_codec_direction_t direction) {
return audio_codec_init_real(audio_codec, direction, true);
return audio_codec_init_real(get_name_to_audio_codec(audio_codec), direction, true);
}
static struct audio_codec_state *audio_codec_init_real(audio_codec_t audio_codec,
struct audio_codec_state *audio_codec_init_cfg(const char *audio_codec_cfg,
audio_codec_direction_t direction) {
return audio_codec_init_real(audio_codec_cfg, direction, true);
}
static struct audio_codec_state *audio_codec_init_real(const char *audio_codec_cfg,
audio_codec_direction_t direction, bool try_init) {
audio_codec_t audio_codec = get_audio_codec(audio_codec_cfg);
int bitrate = get_audio_codec_bitrate(audio_codec_cfg);
void *state = NULL;
int index;
#ifdef BUILD_LIBRARIES
@@ -160,7 +171,7 @@ static struct audio_codec_state *audio_codec_init_real(audio_codec_t audio_codec
continue;
for(unsigned int j = 0; audio_codecs[i]->supported_codecs[j] != AC_NONE; ++j) {
if(audio_codecs[i]->supported_codecs[j] == audio_codec) {
state = audio_codecs[i]->init(audio_codec, direction, try_init);
state = audio_codecs[i]->init(audio_codec, direction, try_init, bitrate);
index = i;
if(state) {
break;
@@ -185,12 +196,13 @@ static struct audio_codec_state *audio_codec_init_real(audio_codec_t audio_codec
struct audio_codec_state *s = (struct audio_codec_state *) malloc(sizeof(struct audio_codec_state));
s->state = calloc(1, sizeof(void**));
s->state = (void **) calloc(1, sizeof(void**));
s->state[0] = state;
s->state_count = 1;
s->index = index;
s->codec = audio_codec;
s->direction = direction;
s->bitrate = bitrate;
s->out = audio_frame2_init();
s->out->ch_count = 1;
@@ -220,9 +232,9 @@ struct audio_codec_state *audio_codec_reconfigure(struct audio_codec_state *old,
audio_frame2 *audio_codec_compress(struct audio_codec_state *s, audio_frame2 *frame)
{
if(frame && s->state_count < frame->ch_count) {
s->state = realloc(s->state, sizeof(void **) * frame->ch_count);
s->state = (void **) realloc(s->state, sizeof(void **) * frame->ch_count);
for(int i = s->state_count; i < frame->ch_count; ++i) {
s->state[i] = audio_codecs[s->index]->init(s->codec, s->direction, false);
s->state[i] = audio_codecs[s->index]->init(s->codec, s->direction, false, s->bitrate);
if(s->state[i] == NULL) {
fprintf(stderr, "Error: initialization of audio codec failed!\n");
return NULL;
@@ -259,9 +271,9 @@ audio_frame2 *audio_codec_compress(struct audio_codec_state *s, audio_frame2 *fr
audio_frame2 *audio_codec_decompress(struct audio_codec_state *s, audio_frame2 *frame)
{
if(s->state_count < frame->ch_count) {
s->state = realloc(s->state, sizeof(void **) * frame->ch_count);
s->state = (void **) realloc(s->state, sizeof(void **) * frame->ch_count);
for(int i = s->state_count; i < frame->ch_count; ++i) {
s->state[i] = audio_codecs[s->index]->init(s->codec, s->direction, false);
s->state[i] = audio_codecs[s->index]->init(s->codec, s->direction, false, 0);
if(s->state[i] == NULL) {
fprintf(stderr, "Error: initialization of audio codec failed!\n");
return NULL;
@@ -317,3 +329,82 @@ const int *audio_codec_get_supported_bps(struct audio_codec_state *s)
return audio_codecs[s->index]->supported_bytes_per_second;
}
audio_codec_t get_audio_codec(const char *codec_str) {
char *codec = strdup(codec_str);
if (strchr(codec, ':')) {
*strchr(codec, ':') = '\0';
}
for(int i = 0; i < audio_codec_info_len; ++i) {
if(strcasecmp(audio_codec_info[i].name, codec) == 0) {
free(codec);
return (audio_codec_t) i;
}
}
free(codec);
return AC_NONE;
}
/**
* Caller must free() the returned buffer
*/
static char *get_val_from_cfg(const char *audio_codec_cfg, const char *key)
{
char *cfg = strdup(audio_codec_cfg);
char *tmp = cfg;
char *item, *save_ptr;
while ((item = strtok_r(cfg, ":", &save_ptr)) != NULL) {
if (strncasecmp(key, item, strlen(key)) == 0) {
free(tmp);
return strdup(item + strlen(key));
}
cfg = NULL;
}
free(tmp);
return NULL;
}
int get_audio_codec_sample_rate(const char *audio_codec_cfg)
{
char *val = get_val_from_cfg(audio_codec_cfg, "sample_rate=");
if (val) {
int ret = atoi(val);
free(val);
return ret;
} else {
return 48000;
}
}
int get_audio_codec_bitrate(const char *audio_codec_cfg)
{
char *val = get_val_from_cfg(audio_codec_cfg, "bitrate=");
if (val) {
int ret = atoi(val);
free(val);
return ret;
} else {
return 0;
}
}
const char *get_name_to_audio_codec(audio_codec_t codec)
{
return audio_codec_info[codec].name;
}
uint32_t get_audio_tag(audio_codec_t codec)
{
return audio_codec_info[codec].tag;
}
audio_codec_t get_audio_codec_to_tag(uint32_t tag)
{
for(int i = 0; i < audio_codec_info_len; ++i) {
if(audio_codec_info[i].tag == tag) {
return (audio_codec_t) i;
}
}
return AC_NONE;
}

View File

@@ -63,7 +63,7 @@ typedef enum {
struct audio_codec {
const audio_codec_t *supported_codecs;
const int *supported_bytes_per_second;
void *(*init)(audio_codec_t, audio_codec_direction_t, bool);
void *(*init)(audio_codec_t, audio_codec_direction_t, bool, int bitrate);
audio_channel *(*compress)(void *, audio_channel *);
audio_channel *(*decompress)(void *, audio_channel *);
void (*done)(void *);
@@ -85,6 +85,7 @@ extern int audio_codec_info_len;
struct audio_codec_state;
struct audio_codec_state *audio_codec_init(audio_codec_t audio_codec, audio_codec_direction_t);
struct audio_codec_state *audio_codec_init_cfg(const char *audio_codec_cfg, audio_codec_direction_t);
struct audio_codec_state *audio_codec_reconfigure(struct audio_codec_state *old,
audio_codec_t audio_codec, audio_codec_direction_t);
audio_frame2 *audio_codec_compress(struct audio_codec_state *, audio_frame2 *);
@@ -94,6 +95,13 @@ void audio_codec_done(struct audio_codec_state *);
void list_audio_codecs(void);
audio_codec_t get_audio_codec(const char *audio_codec_cfg);
int get_audio_codec_sample_rate(const char *audio_codec_cfg);
int get_audio_codec_bitrate(const char *audio_codec_cfg);
const char *get_name_to_audio_codec(audio_codec_t codec);
uint32_t get_audio_tag(audio_codec_t codec);
audio_codec_t get_audio_codec_to_tag(uint32_t audio_tag);
#ifdef __cplusplus
}
#endif

View File

@@ -60,7 +60,8 @@
#define MAGIC 0x552bca11
static void *dummy_pcm_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool try_init);
static void *dummy_pcm_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool try_init,
int bitrate);
static audio_channel *dummy_pcm_compress(void *, audio_channel *);
static audio_channel *dummy_pcm_decompress(void *, audio_channel *);
static void dummy_pcm_done(void *);
@@ -69,10 +70,12 @@ struct dummy_pcm_codec_state {
uint32_t magic;
};
static void *dummy_pcm_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool try_init)
static void *dummy_pcm_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool try_init,
int bitrate)
{
UNUSED(direction);
UNUSED(try_init);
UNUSED(bitrate);
assert(audio_codec == AC_PCM);
struct dummy_pcm_codec_state *s = malloc(sizeof(struct dummy_pcm_codec_state));
s->magic = MAGIC;

View File

@@ -55,7 +55,7 @@
#include "audio/codec/libavcodec.h"
#include <libavcodec/avcodec.h>
#if LIBAVCODEC_VERSION_MAJOR >= 55
#if LIBAVCODEC_VERSION_MAJOR >= 54
#include <libavutil/channel_layout.h>
#endif
#include <libavutil/mem.h>
@@ -68,7 +68,7 @@
#define MAGIC 0xb135ca11
#ifndef HAVE_AVCODEC_ENCODE_VIDEO2
#if LIBAVCODEC_VERSION_MAJOR < 54
#define AV_CODEC_ID_PCM_ALAW CODEC_ID_PCM_ALAW
#define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW
#define AV_CODEC_ID_ADPCM_IMA_WAV CODEC_ID_ADPCM_IMA_WAV
@@ -79,7 +79,7 @@
#endif
static void *libavcodec_init(audio_codec_t audio_codec, audio_codec_direction_t direction,
bool try_init);
bool try_init, int bitrate);
static audio_channel *libavcodec_compress(void *, audio_channel *);
static audio_channel *libavcodec_decompress(void *, audio_channel *);
static void libavcodec_done(void *);
@@ -101,7 +101,7 @@ static const audio_codec_t_to_codec_id_mapping_t mapping[] =
[AC_MULAW] = { .codec_id = AV_CODEC_ID_PCM_MULAW },
[AC_ADPCM_IMA_WAV] = { .codec_id = AV_CODEC_ID_ADPCM_IMA_WAV },
[AC_SPEEX] = { .codec_id = AV_CODEC_ID_SPEEX },
#if LIBAVCODEC_VERSION_MAJOR >= 55
#if LIBAVCODEC_VERSION_MAJOR >= 54
[AC_OPUS] = { .codec_id = AV_CODEC_ID_OPUS },
#endif
[AC_G722] = { .codec_id = AV_CODEC_ID_ADPCM_G722 },
@@ -124,6 +124,8 @@ struct libavcodec_codec_state {
void *samples;
int change_bps_to;
int bitrate;
};
/**
@@ -135,7 +137,8 @@ struct libavcodec_codec_state {
* @retval NULL if initialization failed
* @retval !=NULL codec state
*/
static void *libavcodec_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool try_init)
static void *libavcodec_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool try_init,
int bitrate)
{
int codec_id = 0;
@@ -176,6 +179,8 @@ static void *libavcodec_init(audio_codec_t audio_codec, audio_codec_direction_t
return NULL;
}
s->bitrate = bitrate;
s->samples = NULL;
av_init_packet(&s->pkt);
@@ -219,7 +224,7 @@ static bool reinitialize_coder(struct libavcodec_codec_state *s, struct audio_de
pthread_mutex_unlock(s->libav_global_lock);
/* put sample parameters */
s->codec_ctx->bit_rate = 64000;
s->codec_ctx->bit_rate = s->bitrate;
s->codec_ctx->sample_rate = desc.sample_rate;
s->change_bps_to = 0;
switch(desc.bps) {
@@ -242,7 +247,7 @@ static bool reinitialize_coder(struct libavcodec_codec_state *s, struct audio_de
}
s->codec_ctx->channels = 1;
#if LIBAVCODEC_VERSION_MAJOR >= 55
#if LIBAVCODEC_VERSION_MAJOR >= 54
s->codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;
#endif
@@ -261,7 +266,7 @@ static bool reinitialize_coder(struct libavcodec_codec_state *s, struct audio_de
s->av_frame->nb_samples = s->codec_ctx->frame_size;
s->av_frame->format = s->codec_ctx->sample_fmt;
#if LIBAVCODEC_VERSION_MAJOR >= 55
#if LIBAVCODEC_VERSION_MAJOR >= 54
s->av_frame->channel_layout = AV_CH_LAYOUT_MONO;
#endif
@@ -455,7 +460,7 @@ static void libavcodec_done(void *state)
free(s->tmp.data);
av_free_packet(&s->pkt);
av_freep(&s->samples);
#if LIBAVCODEC_VERSION_MAJOR >= 55
#if LIBAVCODEC_VERSION_MAJOR >= 54
avcodec_free_frame(&s->av_frame);
#else
av_free(s->av_frame);

View File

@@ -161,7 +161,7 @@ int audio_play_alsa_reconfigure(void *state, int quant_samples, int channels,
rc = snd_pcm_hw_params_set_rate_resample(s->handle,
params, val);
if(rc < 0) {
fprintf(stderr, "[ALSA play.] Warnings: Unable to set resampling: %s\n",
fprintf(stderr, "[ALSA play.] Warning: Unable to set resampling: %s\n",
snd_strerror(rc));
}
@@ -177,18 +177,19 @@ int audio_play_alsa_reconfigure(void *state, int quant_samples, int channels,
return FALSE;
}
/* Set period size to 1 frame. */
/* Set period to its minimal size.
* Do not use snd_pcm_hw_params_set_period_size_near,
* since it allows to set also unsupported value without notifying.
* See also http://www.alsa-project.org/main/index.php/FramesPeriods */
frames = 1;
dir = 1;
rc = snd_pcm_hw_params_set_period_size_near(s->handle,
rc = snd_pcm_hw_params_set_period_time_min(s->handle,
params, &frames, &dir);
if (rc < 0) {
fprintf(stderr, "cannot set period time: %s\n",
fprintf(stderr, "[ALSA play.] Warning: cannot set period time: %s\n",
snd_strerror(rc));
return FALSE;
}
val = BUFFER_MIN * 1000;
dir = 1;
rc = snd_pcm_hw_params_set_buffer_time_min(s->handle, params,

View File

@@ -423,28 +423,34 @@ void decklink_put_frame(void *state, struct audio_frame *frame)
#else
unsigned int sampleFramesWritten;
#endif
char *data = frame->data;
// tmp_frame is used if we need to perform 1->2 channel multiplication
struct audio_frame tmp_frame;
tmp_frame.data = NULL;
/* we got probably count that cannot be played directly (probably 1) */
/* we got probably channel count that cannot be played directly (probably 1) */
if(s->output_audio_channel_count != s->audio_desc.ch_count) {
assert(s->audio_desc.ch_count == 1); /* only reasonable value so far */
if (sampleFrameCount * s->output_audio_channel_count
* frame->bps > frame->max_size) {
fprintf(stderr, "[decklink] audio buffer overflow!\n");
sampleFrameCount = frame->max_size /
(s->output_audio_channel_count * frame->bps);
frame->data_len = sampleFrameCount *
(frame->ch_count * frame->bps);
}
assert(s->audio_desc.ch_count == 1); /* only supported value so far */
memcpy(&tmp_frame, frame, sizeof(tmp_frame));
// allocate enough space to hold resulting data
tmp_frame.max_size = sampleFrameCount * s->output_audio_channel_count
* frame->bps;
tmp_frame.data = (char *) malloc(tmp_frame.max_size);
memcpy(tmp_frame.data, frame->data, frame->data_len);
audio_frame_multiply_channel(frame,
audio_frame_multiply_channel(&tmp_frame,
s->output_audio_channel_count);
data = tmp_frame.data;
}
s->deckLinkOutput->ScheduleAudioSamples (frame->data, sampleFrameCount, 0,
s->deckLinkOutput->ScheduleAudioSamples (data, sampleFrameCount, 0,
0, &sampleFramesWritten);
if(sampleFramesWritten != sampleFrameCount)
fprintf(stderr, "[decklink] audio buffer underflow!\n");
free(tmp_frame.data);
}
int decklink_reconfigure(void *state, int quant_samples, int channels,

View File

@@ -69,7 +69,7 @@
#define MAX_PORTS 64
struct state_jack_playback {
const char *jack_ports_pattern;
char *jack_ports_pattern;
int jack_sample_rate;
jack_client_t *client;
jack_port_t *output_port[MAX_PORTS];
@@ -78,6 +78,7 @@ struct state_jack_playback {
float *converted;
#ifdef HAVE_SPEEX
float *converted_resampled;
size_t converted_resampled_size;
SpeexResamplerState *resampler;
#endif
@@ -190,7 +191,7 @@ void * audio_play_jack_init(char *cfg)
s = calloc(1, sizeof(struct state_jack_playback));
s->jack_ports_pattern = cfg;
s->jack_ports_pattern = strdup(cfg);
if(!s) {
fprintf(stderr, "[JACK playback] Unable to allocate memory.\n");
@@ -287,7 +288,8 @@ int audio_play_jack_reconfigure(void *state, int quant_samples, int channels,
if(s->resampler) {
speex_resampler_destroy(s->resampler);
}
s->converted_resampled = (float *) malloc(sizeof(float) * s->jack_sample_rate);
s->converted_resampled_size = sizeof(float) * s->jack_sample_rate;
s->converted_resampled = (float *) malloc(s->converted_resampled_size);
{
int err;
@@ -337,7 +339,7 @@ void audio_play_jack_put_frame(void *state, struct audio_frame *frame)
int2float((char *) s->converted, (char *) s->converted, converted_size);
#ifdef HAVE_SPEEX
spx_uint32_t in_len = channel_size / frame->bps;
spx_uint32_t out_len;
spx_uint32_t out_len = s->converted_resampled_size;
speex_resampler_process_float(s->resampler,
i,
s->converted,
@@ -364,6 +366,7 @@ void audio_play_jack_done(void *state)
#endif
free(s->channel);
free(s->converted);
free(s->jack_ports_pattern);
for(i = 0; i < MAX_PORTS; ++i) {
ring_buffer_destroy(s->data[i]);
}

View File

@@ -80,15 +80,11 @@ void audio_frame2_allocate(audio_frame2 *frame, int nr_channels, int max_size)
{
assert(nr_channels <= MAX_AUDIO_CHANNELS);
audio_frame2_reset(frame);
frame->max_size = max_size;
frame->ch_count = nr_channels;
for(int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
free(frame->data[i]);
frame->data[i] = NULL;
frame->data_len[i] = 0;
}
for(int i = 0; i < nr_channels; ++i) {
frame->data[i] = malloc(max_size);
}
@@ -96,6 +92,7 @@ void audio_frame2_allocate(audio_frame2 *frame, int nr_channels, int max_size)
void audio_frame2_append(audio_frame2 *dest, audio_frame2 *src)
{
assert(src->ch_count == dest->ch_count || dest->ch_count == 0);
dest->bps = src->bps;
int new_max_size = dest->max_size;
for (int i = 0; i < src->ch_count; ++i) {
@@ -126,9 +123,13 @@ int audio_frame2_get_sample_count(audio_frame2 *frame)
void audio_frame2_reset(audio_frame2 *frame)
{
for (int i = 0; i < frame->ch_count; ++i) {
for(int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
frame->data_len[i] = 0;
free(frame->data[i]);
frame->data[i] = NULL;
}
frame->max_size = 0;
frame->ch_count = 0;
}
static double get_normalized(char *in, int bps) {
@@ -251,19 +252,15 @@ static inline int32_t format_from_in_bps(const char * in, int bps) {
}
static inline void format_to_out_bps(char *out, int bps, int32_t out_value) {
uint32_t mask;
if(bps == sizeof(uint32_t)) {
mask = 0xffffffffu - 1;
} else {
mask = ((1 << (bps * 8)) - 1);
uint32_t mask = ((1ll << (bps * 8)) - 1);
// clamp
if(out_value > (1ll << (bps * 8 - 1)) -1) {
out_value = (1ll << (bps * 8 - 1)) -1;
}
if(out_value > (1 << (bps * 8 - 1)) -1) {
out_value = (1 << (bps * 8 - 1)) -1;
}
if(out_value < -(1 << (bps * 8 - 1))) {
out_value = -(1 << (bps * 8 - 1));
if(out_value < -(1ll << (bps * 8 - 1))) {
out_value = -(1ll << (bps * 8 - 1));
}
uint32_t out_value_formatted = (1 * (0x1 & (out_value >> 31))) << (bps * 8 - 1) | (out_value & mask);
@@ -480,32 +477,3 @@ void audio_channel_mux(audio_frame2 *frame, int index, audio_channel *channel)
frame->sample_rate = channel->sample_rate;
}
audio_codec_t get_audio_codec_to_name(const char *codec) {
for(int i = 0; i < audio_codec_info_len; ++i) {
if(strcasecmp(audio_codec_info[i].name, codec) == 0) {
return i;
}
}
return AC_NONE;
}
const char *get_name_to_audio_codec(audio_codec_t codec)
{
return audio_codec_info[codec].name;
}
uint32_t get_audio_tag(audio_codec_t codec)
{
return audio_codec_info[codec].tag;
}
audio_codec_t get_audio_codec_to_tag(uint32_t tag)
{
for(int i = 0; i < audio_codec_info_len; ++i) {
if(audio_codec_info[i].tag == tag) {
return i;
}
}
return AC_NONE;
}

View File

@@ -72,11 +72,6 @@ struct audio_desc audio_desc_from_audio_channel(audio_channel *);
void audio_channel_demux(audio_frame2 *, int, audio_channel*);
void audio_channel_mux(audio_frame2 *, int, audio_channel*);
audio_codec_t get_audio_codec_to_name(const char *name);
const char *get_name_to_audio_codec(audio_codec_t codec);
uint32_t get_audio_tag(audio_codec_t codec);
audio_codec_t get_audio_codec_to_tag(uint32_t audio_tag);
/**
* Changes bps for everey sample.
*

View File

@@ -1,166 +0,0 @@
/**
* @file capture_filter/logo.c
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2013 CESNET z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif /* HAVE_CONFIG_H */
#include "src/cesnet-logo-2.c"
#include "capture_filter.h"
#include "debug.h"
#include "video.h"
#include "video_codec.h"
struct state_capture_filter_logo {
int x, y;
};
static int init(struct module *parent, const char *cfg, void **state);
static void done(void *state);
static struct video_frame *filter(void *state, struct video_frame *in);
static int init(struct module *parent, const char *cfg, void **state)
{
UNUSED(parent);
struct state_capture_filter_logo *s = (struct state_capture_filter_logo *)
calloc(1, sizeof(struct state_capture_filter_logo));
s->x = s->y = -1;
if (cfg) {
if (strcasecmp(cfg, "help") == 0) {
printf("Draws overlay logo over video:\n\n");
printf("'logo' usage:\n");
printf("\tlogo[:<x>[:<y>]]\n\n");
free(s);
return 1;
}
char *tmp = strdup(cfg);
char *save_ptr = NULL;
char *item;
if ((item = strtok_r(tmp, ":", &save_ptr))) {
s->x = atoi(item);
if ((item = strtok_r(NULL, ":", &save_ptr))) {
s->y = atoi(item);
}
}
free(tmp);
}
*state = s;
return 0;
}
static void done(void *state)
{
free(state);
}
static struct video_frame *filter(void *state, struct video_frame *in)
{
struct state_capture_filter_logo *s = (struct state_capture_filter_logo *)
state;
const int width = cesnet_logo.width;
const int height = cesnet_logo.height;
int linesize = width * 3;
decoder_t decoder, coder;
decoder = get_decoder_from_to(in->color_spec, RGB, true);
coder = get_decoder_from_to(RGB, in->color_spec, true);
int rect_x = s->x;
int rect_y = s->y;
if (decoder == NULL || coder == NULL)
return in;
if (rect_x < 0 || rect_x + width > (int) in->tiles[0].width) {
rect_x = in->tiles[0].width - width;
}
rect_x = (rect_x / get_pf_block_size(in->color_spec)) * get_pf_block_size(in->color_spec);
if (rect_y < 0 || rect_y + height > (int) in->tiles[0].height) {
rect_y = in->tiles[0].height - height;
}
if (rect_x < 0 || rect_y < 0)
return in;
unsigned char *segment = (unsigned char *) malloc(width * height * 3);
for (int y = 0; y < height; ++y) {
decoder(segment + y * linesize, (unsigned char *) in->tiles[0].data + (y + rect_y) *
vc_get_linesize(in->tiles[0].width, in->color_spec) +
vc_get_linesize(rect_x, in->color_spec), linesize,
0, 8, 16);
}
unsigned char *image_data = segment;
const unsigned char *overlay_data = cesnet_logo.pixel_data;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
int alpha = overlay_data[3];
for (int i = 0; i < 3; ++i) {
*image_data = (*image_data * (255 - alpha) + *overlay_data++ * alpha) / 255;
image_data++;
}
overlay_data++; // skip alpha
}
}
for (int y = 0; y < height; ++y) {
coder((unsigned char *) in->tiles[0].data + (rect_y + y) *
vc_get_linesize(in->tiles[0].width, in->color_spec) +
vc_get_linesize(rect_x, in->color_spec),
segment + y * linesize,
vc_get_linesize(width, in->color_spec), 0, 8, 16);
}
free(segment);
return in;
}
struct capture_filter_info capture_filter_logo = {
.name = "logo",
.init = init,
.done = done,
.filter = filter,
};

236
src/capture_filter/logo.cpp Normal file
View File

@@ -0,0 +1,236 @@
/**
* @file capture_filter/logo.c
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2013 CESNET z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif /* HAVE_CONFIG_H */
#include <fstream>
#include <iostream>
#include "capture_filter.h"
#include "debug.h"
#include "video.h"
#include "video_codec.h"
struct state_capture_filter_logo {
unsigned char *logo;
unsigned int width, height;
int x, y;
};
static int init(struct module *parent, const char *cfg, void **state);
static void done(void *state);
static struct video_frame *filter(void *state, struct video_frame *in);
using namespace std;
static bool load_logo_data_from_file(struct state_capture_filter_logo *s, const char *filename) {
try {
string line;
ifstream file(filename, ifstream::in | ifstream::binary);
file.exceptions(ifstream::failbit | ifstream::badbit );
getline(file, line);
if (!file.good() || line != "P7") {
throw string("Only logo in PAM format is currently supported.");
}
getline(file, line);
while (!file.eof()) {
if (line.compare(0, strlen("WIDTH"), "WIDTH") == 0) {
s->width = atoi(line.c_str() + strlen("WIDTH "));
} else if (line.compare(0, strlen("HEIGHT"), "HEIGHT") == 0) {
s->height = atoi(line.c_str() + strlen("HEIGHT "));
} else if (line.compare(0, strlen("DEPTH"), "DEPTH") == 0) {
if (atoi(line.c_str() + strlen("DEPTH ")) != 4) {
throw string("Only depth 4 is supported.");
}
} else if (line.compare(0, strlen("MAXVAL"), "MAXVAL") == 0) {
if (atoi(line.c_str() + strlen("MAXVAL ")) != 255) {
throw string("Only supported maxval is 255.");
}
} else if (line.compare(0, strlen("TUPLETYPE"), "MAXVAL") == 0) {
if (line.compare("TUPLTYPE RGB_ALPHA") != 0) {
throw string("Only supported tuple type is RGBA_APLHA.");
}
} else if (line.compare(0, strlen("ENDHDR"), "ENDHDR") == 0) {
break;
}
getline(file, line);
}
int datalen = 4 * s->width * s->height;
s->logo = (unsigned char *) malloc(datalen);
file.read((char *) s->logo, datalen);
if (file.eof()) {
throw string("Unable to load logo data from file.");
}
file.close();
} catch (string const & s) {
cerr << s << endl;
return false;
} catch (exception const & e) {
cerr << e.what() << endl;
return false;
} catch (...) {
return false;
}
return true;
}
static int init(struct module *parent, const char *cfg, void **state)
{
UNUSED(parent);
struct state_capture_filter_logo *s = (struct state_capture_filter_logo *)
calloc(1, sizeof(struct state_capture_filter_logo));
s->x = s->y = -1;
if (!cfg || strcasecmp(cfg, "help") == 0) {
printf("Draws overlay logo over video:\n\n");
printf("'logo' usage:\n");
printf("\tlogo:<file>[:<x>[:<y>]]\n");
printf("\t\t<file> - is path to logo to be added in PAM format with alpha\n");
free(s);
return 1;
}
char *tmp = strdup(cfg);
char *save_ptr = NULL;
char *item;
if ((item = strtok_r(tmp, ":", &save_ptr)) == NULL) {
fprintf(stderr, "File name with logo required!\n");
return -1;
}
if (!load_logo_data_from_file(s, item)) {
free(s);
return -1;
}
if ((item = strtok_r(tmp, ":", &save_ptr))) {
s->x = atoi(item);
if ((item = strtok_r(NULL, ":", &save_ptr))) {
s->y = atoi(item);
}
}
free(tmp);
*state = s;
return 0;
}
static void done(void *state)
{
struct state_capture_filter_logo *s = (struct state_capture_filter_logo *)
state;
free(s->logo);
free(state);
}
static struct video_frame *filter(void *state, struct video_frame *in)
{
struct state_capture_filter_logo *s = (struct state_capture_filter_logo *)
state;
int linesize = s->width * 3;
decoder_t decoder, coder;
decoder = get_decoder_from_to(in->color_spec, RGB, true);
coder = get_decoder_from_to(RGB, in->color_spec, true);
int rect_x = s->x;
int rect_y = s->y;
if (decoder == NULL || coder == NULL)
return in;
if (rect_x < 0 || rect_x + s->width > in->tiles[0].width) {
rect_x = in->tiles[0].width - s->width;
}
rect_x = (rect_x / get_pf_block_size(in->color_spec)) * get_pf_block_size(in->color_spec);
if (rect_y < 0 || rect_y + s->height > in->tiles[0].height) {
rect_y = in->tiles[0].height - s->height;
}
if (rect_x < 0 || rect_y < 0)
return in;
unsigned char *segment = (unsigned char *) malloc(s->width * s->height * 3);
for (unsigned int y = 0; y < s->height; ++y) {
decoder(segment + y * linesize, (unsigned char *) in->tiles[0].data + (y + rect_y) *
vc_get_linesize(in->tiles[0].width, in->color_spec) +
vc_get_linesize(rect_x, in->color_spec), linesize,
0, 8, 16);
}
unsigned char *image_data = segment;
const unsigned char *overlay_data = s->logo;
for (unsigned int y = 0; y < s->height; ++y) {
for (unsigned int x = 0; x < s->width; ++x) {
int alpha = overlay_data[3];
for (int i = 0; i < 3; ++i) {
*image_data = (*image_data * (255 - alpha) + *overlay_data++ * alpha) / 255;
image_data++;
}
overlay_data++; // skip alpha
}
}
for (unsigned int y = 0; y < s->height; ++y) {
coder((unsigned char *) in->tiles[0].data + (rect_y + y) *
vc_get_linesize(in->tiles[0].width, in->color_spec) +
vc_get_linesize(rect_x, in->color_spec),
segment + y * linesize,
vc_get_linesize(s->width, in->color_spec), 0, 8, 16);
}
free(segment);
return in;
}
struct capture_filter_info capture_filter_logo = {
"logo",
init,
done,
filter,
};

File diff suppressed because it is too large Load Diff

View File

@@ -300,10 +300,22 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message)
abort();
}
struct msg_sender *msg_audio = (struct msg_sender *) malloc(sizeof(struct msg_sender));
memcpy(msg_audio, msg, sizeof(struct msg_sender));
if (msg_audio->type == SENDER_MSG_CHANGE_PORT) {
msg->port = atoi(suffix(message, "sender-port "));
}
enum module_class path_sender[] = { MODULE_CLASS_SENDER, MODULE_CLASS_NONE };
enum module_class path_sender_audio[] = { MODULE_CLASS_AUDIO, MODULE_CLASS_SENDER, MODULE_CLASS_NONE };
char path_audio[1024];
memcpy(path_audio, path, sizeof(path_audio));
append_message_path(path, sizeof(path), path_sender);
append_message_path(path_audio, sizeof(path_audio), path_sender_audio);
resp =
send_message(s->root_module, path, (struct message *) msg);
send_message(s->root_module, path_audio, (struct message *) msg_audio);
} else if (prefix_matches(message, "receiver-port ")) {
struct msg_receiver *msg =
(struct msg_receiver *)
@@ -349,7 +361,7 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message)
char *compress = suffix(message, "compress ");
if(prefix_matches(compress, "param ")) {
compress = suffix(compress, " param");
compress = suffix(compress, "param ");
msg->what = CHANGE_PARAMS;
} else {
msg->what = CHANGE_COMPRESS;
@@ -357,7 +369,7 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message)
strncpy(msg->config_string, compress, sizeof(msg->config_string) - 1);
if(!resp) {
enum module_class path_compress[] = { MODULE_CLASS_COMPRESS, MODULE_CLASS_NONE };
enum module_class path_compress[] = { MODULE_CLASS_SENDER, MODULE_CLASS_COMPRESS, MODULE_CLASS_NONE };
append_message_path(path, sizeof(path), path_compress);
resp = send_message(s->root_module, path, (struct message *) msg);
}

View File

@@ -41,6 +41,8 @@ bool verbose = false;
bool ldgm_device_gpu = false;
const char *window_title = NULL;
int rxtx_mode; // MODE_SENDER, MODE_RECEIVER or both
int initialize_video_capture(struct module *parent,

View File

@@ -96,6 +96,8 @@ extern bool verbose;
extern bool ldgm_device_gpu;
extern const char *window_title;
#define MODE_SENDER 1
#define MODE_RECEIVER 2
extern int rxtx_mode;

View File

@@ -13,7 +13,7 @@
#include <libavutil/opt.h>
#include <libavutil/pixfmt.h>
#if !defined(HAVE_AVCODEC_ENCODE_VIDEO2) || (LIBAVCODEC_VERSION_MAJOR < 55)
#if LIBAVCODEC_VERSION_MAJOR < 54
#define AV_PIX_FMT_NONE PIX_FMT_NONE
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P

View File

@@ -127,6 +127,7 @@
#define OPT_CONTROL_PORT (('C' << 8) | 'P')
#define OPT_VERBOSE (('V' << 8) | 'E')
#define OPT_LDGM_DEVICE (('L' << 8) | 'D')
#define OPT_WINDOW_TITLE (('W' << 8) | 'T')
#define MAX_CAPTURE_COUNT 17
@@ -433,7 +434,6 @@ int main(int argc, char *argv[])
const char *requested_audio_fec = DEFAULT_AUDIO_FEC;
char *audio_channel_map = NULL;
const char *audio_scale = "mixauto";
rtsp_serv_t* rtsp_server = NULL;
bool isStd = FALSE;
int recv_port_number = PORT_BASE;
int send_port_number = PORT_BASE;
@@ -457,14 +457,13 @@ int main(int argc, char *argv[])
struct state_uv *uv;
int ch;
audio_codec_t audio_codec = AC_PCM;
const char *audio_codec = "PCM";
pthread_t receiver_thread_id,
capture_thread_id;
bool receiver_thread_started = false,
capture_thread_started = false;
bool receiver_thread_started = false,
capture_thread_started = false;
unsigned display_flags = 0;
int compressed_audio_sample_rate = 48000;
int ret;
struct vidcap_params *audio_cap_dev;
long packet_rate;
@@ -524,6 +523,7 @@ int main(int argc, char *argv[])
{"encryption", required_argument, 0, OPT_ENCRYPTION},
{"verbose", no_argument, 0, OPT_VERBOSE},
{"ldgm-device", required_argument, 0, OPT_LDGM_DEVICE},
{"window-title", required_argument, 0, OPT_WINDOW_TITLE},
{0, 0, 0, 0}
};
int option_index = 0;
@@ -553,11 +553,11 @@ int main(int argc, char *argv[])
return 0;
}
requested_display = optarg;
if(strchr(optarg, ':')) {
char *delim = strchr(optarg, ':');
*delim = '\0';
display_cfg = delim + 1;
}
if(strchr(optarg, ':')) {
char *delim = strchr(optarg, ':');
*delim = '\0';
display_cfg = delim + 1;
}
break;
case 't':
if (!strcmp(optarg, "help")) {
@@ -635,9 +635,9 @@ int main(int argc, char *argv[])
requested_video_fec = optarg;
}
break;
case 'h':
usage();
return 0;
case 'h':
usage();
return 0;
case 'P':
if(strchr(optarg, ':')) {
char *save_ptr = NULL;
@@ -741,12 +741,8 @@ int main(int argc, char *argv[])
list_audio_codecs();
return EXIT_SUCCESS;
}
if(strchr(optarg, ':')) {
compressed_audio_sample_rate = atoi(strchr(optarg, ':')+1);
*strchr(optarg, ':') = '\0';
}
audio_codec = get_audio_codec_to_name(optarg);
if(audio_codec == AC_NONE) {
audio_codec = optarg;
if(get_audio_codec(optarg) == AC_NONE) {
fprintf(stderr, "Unknown audio codec entered: \"%s\"\n",
optarg);
return EXIT_FAIL_USAGE;
@@ -771,6 +767,9 @@ int main(int argc, char *argv[])
ldgm_device_gpu = false;
}
break;
case OPT_WINDOW_TITLE:
window_title = optarg;
break;
case '?':
default:
usage();
@@ -797,7 +796,7 @@ int main(int argc, char *argv[])
printf("Audio playback : %s\n", audio_recv);
printf("MTU : %d B\n", requested_mtu);
printf("Video compression: %s\n", requested_compression);
printf("Audio codec : %s\n", get_name_to_audio_codec(audio_codec));
printf("Audio codec : %s\n", get_name_to_audio_codec(get_audio_codec(audio_codec)));
printf("Network protocol : %s\n", video_rxtx::get_name(video_protocol));
printf("Audio FEC : %s\n", requested_audio_fec);
printf("Video FEC : %s\n", requested_video_fec);
@@ -831,17 +830,17 @@ int main(int argc, char *argv[])
}
#ifdef WIN32
WSADATA wsaData;
int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(err != 0) {
fprintf(stderr, "WSAStartup failed with error %d.", err);
return EXIT_FAILURE;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
fprintf(stderr, "Counld not found usable version of Winsock.\n");
WSACleanup();
return EXIT_FAILURE;
}
WSADATA wsaData;
int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(err != 0) {
fprintf(stderr, "WSAStartup failed with error %d.", err);
return EXIT_FAILURE;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
fprintf(stderr, "Counld not found usable version of Winsock.\n");
WSACleanup();
return EXIT_FAILURE;
}
#endif
if(control_init(control_port, &control, &root_mod) != 0) {
@@ -866,7 +865,7 @@ int main(int argc, char *argv[])
jack_cfg, requested_audio_fec, requested_encryption,
audio_channel_map,
audio_scale, echo_cancellation, ipv6, requested_mcast_if,
audio_codec, compressed_audio_sample_rate, isStd, packet_rate);
audio_codec, isStd, packet_rate);
if(!uv->audio)
goto cleanup;
@@ -957,11 +956,14 @@ int main(int argc, char *argv[])
display_device, requested_mtu,
argc, argv);
}else if (video_protocol == H264_STD) {
rtps_types_t avType;
if(strcmp("none", vidcap_params_get_driver(vidcap_params_head)) != 0 && (strcmp("none",audio_send) != 0)) avType = avStdDyn; //AVStream
else if((strcmp("none",audio_send) != 0)) avType = audioPCMUdyn; //AStream
rtps_types_t avType;
if(strcmp("none", vidcap_params_get_driver(vidcap_params_head)) != 0 && (strcmp("none",audio_send) != 0)) avType = avStdDyn; //AVStream
else if((strcmp("none",audio_send) != 0)) avType = audioPCMUdyn; //AStream
else if(strcmp("none", vidcap_params_get_driver(vidcap_params_head))) avType = videoH264; //VStream
else printf("[RTSP SERVER CHECK] no stream type... check capture devices input...\n");
else {
printf("[RTSP SERVER CHECK] no stream type... check capture devices input...\n");
return EXIT_FAIL_USAGE;
}
uv->state_video_rxtx = new h264_rtp_video_rxtx(&root_mod, video_exporter,
requested_compression, requested_encryption,
@@ -1063,10 +1065,6 @@ cleanup:
vidcap_params_head = next;
}
#ifdef HAVE_RTSP_SERVER
if(rtsp_server) c_stop_server(rtsp_server);
#endif
module_done(&root_mod);
free(uv);

View File

@@ -107,17 +107,17 @@ struct state_audio_decoder {
unsigned int channel_remapping:1;
struct channel_map channel_map;
struct scale_data *scale;
struct scale_data *scale; ///< contains scaling metadata if we want to perform audio scaling
bool fixed_scale;
audio_frame2 *received_frame;
audio_frame2 *received_frame; ///< auxiliary buffer that holds undecoded audio frame data from network
struct audio_codec_state *audio_decompress;
struct resampler *resampler;
struct audio_desc saved_desc;
uint32_t saved_audio_tag;
audio_frame2 *decoded; // for statistics
audio_frame2 *decoded; ///< buffer that keeps audio samples from last 5 seconds (for statistics)
struct openssl_decrypt *decrypt;
};
@@ -434,6 +434,7 @@ int decode_audio_frame(struct coded_data *cdata, void *data)
sample_rate, input_channels, input_channels == 1 ? "": "s", bps * 8,
get_name_to_audio_codec(get_audio_codec_to_tag(audio_tag)));
audio_frame2_reset(decoder->decoded);
s->buffer.bps = device_bps;
s->buffer.ch_count = output_channels;
@@ -503,21 +504,21 @@ int decode_audio_frame(struct coded_data *cdata, void *data)
audio_frame2 *resampled = resampler_resample(decoder->resampler, decompressed);
s->buffer.data_len = resampled->data_len[0] * output_channels;
if((int) s->buffer.max_size < s->buffer.data_len) {
free(s->buffer.data);
s->buffer.max_size = s->buffer.data_len;
s->buffer.data = (char *) malloc(s->buffer.max_size);
size_t new_data_len = s->buffer.data_len + resampled->data_len[0] * output_channels;
if((int) s->buffer.max_size < new_data_len) {
s->buffer.max_size = new_data_len;
s->buffer.data = (char *) realloc(s->buffer.data, new_data_len);
}
memset(s->buffer.data, 0, s->buffer.data_len);
memset(s->buffer.data + s->buffer.data_len, 0, new_data_len - s->buffer.data_len);
// there is a mapping for channel
for(int channel = 0; channel < resampled->ch_count; ++channel) {
if(decoder->channel_remapping) {
if(channel < decoder->channel_map.size) {
for(int i = 0; i < decoder->channel_map.sizes[channel]; ++i) {
mux_and_mix_channel(s->buffer.data, resampled->data[channel],
mux_and_mix_channel(s->buffer.data + s->buffer.data_len,
resampled->data[channel],
resampled->bps, resampled->data_len[channel],
output_channels, decoder->channel_map.map[channel][i],
decoder->scale[decoder->fixed_scale ? 0 :
@@ -525,11 +526,13 @@ int decode_audio_frame(struct coded_data *cdata, void *data)
}
}
} else {
mux_and_mix_channel(s->buffer.data, resampled->data[channel], resampled->bps,
mux_and_mix_channel(s->buffer.data + s->buffer.data_len, resampled->data[channel],
resampled->bps,
resampled->data_len[channel], output_channels, channel,
decoder->scale[decoder->fixed_scale ? 0 : input_channels].scale);
}
}
s->buffer.data_len = new_data_len;
audio_frame2_append(decoder->decoded, resampled);

View File

@@ -349,7 +349,9 @@ static socket_udp *udp_init4(const char *addr, const char *iface,
sizeof(udpbufsize)) != 0) {
debug_msg("WARNING: Unable to increase UDP recvbuffer\n");
}
#if 0
// please note that we currently need these 2 options on MSW if we want
// to re-bind socket on runtime, otherwise bind() would return an error if
// binding to same port that was previously bound and closed
#ifdef SO_REUSEPORT
if (SETSOCKOPT
(s->fd, SOL_SOCKET, SO_REUSEPORT, (int *)&reuse,
@@ -364,7 +366,6 @@ static socket_udp *udp_init4(const char *addr, const char *iface,
socket_error("setsockopt SO_REUSEADDR");
return NULL;
}
#endif
s_in.sin_family = AF_INET;
s_in.sin_addr.s_addr = INADDR_ANY;
s_in.sin_port = htons(rx_port);

View File

@@ -174,60 +174,60 @@ struct pbuf *pbuf_init(void)
static void add_coded_unit(struct pbuf_node *node, rtp_packet * pkt)
{
/* Add "pkt" to the frame represented by "node". The "node" has */
/* previously been created, and has some coded data already... */
/* Add "pkt" to the frame represented by "node". The "node" has */
/* previously been created, and has some coded data already... */
/* New arrivals are added at the head of the list, which is stored */
/* in descending order of packets as they arrive (NOT necessarily */
/* descending sequence number order, as the network might reorder) */
/* New arrivals are added at the head of the list, which is stored */
/* in descending order of packets as they arrive (NOT necessarily */
/* descending sequence number order, as the network might reorder) */
struct coded_data *tmp, *curr, *prv;
struct coded_data *tmp, *curr, *prv;
assert(node->rtp_timestamp == pkt->ts);
assert(node->cdata != NULL);
assert(node->rtp_timestamp == pkt->ts);
assert(node->cdata != NULL);
tmp = malloc(sizeof(struct coded_data));
if (tmp == NULL) {
/* this is bad, out of memory, drop the packet... */
free(pkt);
return;
}
tmp->seqno = pkt->seq;
tmp->data = pkt;
node->mbit |= pkt->m;
if((int16_t)(tmp->seqno - node->cdata->seqno) > 0){
tmp->prv = NULL;
tmp->nxt = node->cdata;
node->cdata->prv = tmp;
node->cdata = tmp;
} else {
curr = node->cdata;
if (curr == NULL){
/* this is bad, out of memory, drop the packet... */
free(pkt);
free_cdata(tmp);
} else {
while (curr != NULL && ((int16_t)(tmp->seqno - curr->seqno) < 0)){
prv = curr;
curr = curr->nxt;
}
if (curr == NULL) {
tmp->nxt = NULL;
tmp->prv = prv;
prv->nxt = tmp;
}else if ((int16_t)(tmp->seqno - curr->seqno) > 0){
tmp->nxt = curr;
tmp->prv = curr->prv;
tmp->prv->nxt = tmp;
curr->prv = tmp;
} else {
/* this is bad, something went terribly wrong... */
tmp = malloc(sizeof(struct coded_data));
if (tmp == NULL) {
/* this is bad, out of memory, drop the packet... */
free(pkt);
free_cdata(tmp);
}
return;
}
tmp->seqno = pkt->seq;
tmp->data = pkt;
node->mbit |= pkt->m;
if((int16_t)(tmp->seqno - node->cdata->seqno) > 0){
tmp->prv = NULL;
tmp->nxt = node->cdata;
node->cdata->prv = tmp;
node->cdata = tmp;
} else {
curr = node->cdata;
if (curr == NULL){
/* this is bad, out of memory, drop the packet... */
free(pkt);
free_cdata(tmp);
} else {
while (curr != NULL && ((int16_t)(tmp->seqno - curr->seqno) < 0)){
prv = curr;
curr = curr->nxt;
}
if (curr == NULL) {
tmp->nxt = NULL;
tmp->prv = prv;
prv->nxt = tmp;
}else if ((int16_t)(tmp->seqno - curr->seqno) > 0){
tmp->nxt = curr;
tmp->prv = curr->prv;
tmp->prv->nxt = tmp;
curr->prv = tmp;
} else {
/* this is bad, something went terribly wrong... */
free(pkt);
free_cdata(tmp);
}
}
}
}
}
static struct pbuf_node *create_new_pnode(rtp_packet * pkt, double playout_delay)
@@ -269,7 +269,6 @@ static struct pbuf_node *create_new_pnode(rtp_packet * pkt, double playout_delay
void pbuf_insert(struct pbuf *playout_buf, rtp_packet * pkt)
{
struct pbuf_node *tmp;
struct pbuf_node *curr;
pbuf_validate(playout_buf);
@@ -315,43 +314,47 @@ void pbuf_insert(struct pbuf *playout_buf, rtp_packet * pkt)
return;
}
if (playout_buf->last->rtp_timestamp < pkt->ts) {
/* Packet belongs to a new frame... */
tmp = create_new_pnode(pkt, playout_buf->playout_delay);
playout_buf->last->nxt = tmp;
tmp->prv = playout_buf->last;
playout_buf->last = tmp;
if (playout_buf->last->rtp_timestamp == pkt->ts) {
/* Packet belongs to last frame in playout_buf this is the */
/* most likely scenario - although... */
add_coded_unit(playout_buf->last, pkt);
} else {
/* Packet belongs to a previous frame... */
curr = playout_buf->last;
while(curr != playout_buf->frst && curr->rtp_timestamp > pkt->ts){
curr = curr->prv;
}
if (curr->rtp_timestamp == pkt->ts) {
/* Packet belongs to a previous existing frame... */
add_coded_unit(curr, pkt);
} else if (curr->rtp_timestamp < pkt->ts){
/* Packet belongs to a new previous frame */
tmp = create_new_pnode(pkt, playout_buf->playout_delay);
tmp->nxt = curr->nxt;
tmp->prv = curr;
curr->nxt->prv = tmp;
curr->nxt = tmp;
} else if (curr == playout_buf->frst) {
tmp = create_new_pnode(pkt, playout_buf->playout_delay);
tmp->nxt = playout_buf->frst;
curr->prv = tmp;
playout_buf->frst = tmp;
} else {
if (pkt->m) {
debug_msg
("Oops... dropped packet with M bit set\n");
if (playout_buf->last->rtp_timestamp < pkt->ts) {
/* Packet belongs to a new frame... */
tmp = create_new_pnode(pkt, playout_buf->playout_delay);
playout_buf->last->nxt = tmp;
playout_buf->last->completed = true;
tmp->prv = playout_buf->last;
playout_buf->last = tmp;
} else {
bool discard_pkt = false;
/* Packet belongs to a previous frame... */
if (playout_buf->frst->rtp_timestamp > pkt->ts) {
debug_msg("A very old packet - discarded\n");
discard_pkt = true;
} else {
debug_msg
("A packet for a previous frame, but might still be useful\n");
struct pbuf_node *curr = playout_buf->last;
while(curr != playout_buf->frst && curr->rtp_timestamp > pkt->ts){
curr = curr->prv;
}
if (curr->rtp_timestamp == pkt->ts) {
/* Packet belongs to a previous existing frame... */
add_coded_unit(curr, pkt);
} else {
/* Packet belongs to a frame that is not present */
discard_pkt = true;
}
}
if (pkt->m && discard_pkt) {
debug_msg
("Oops... dropped packet with M bit set\n");
}
if (discard_pkt) {
free(pkt);
}
}
free(pkt);
}
}
pbuf_validate(playout_buf);
}
@@ -462,37 +465,6 @@ pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time,
return 0;
}
int
audio_pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time,
decode_frame_t decode_func, void *data)
{
/* Find the first complete frame that has reached it's playout */
/* time, and decode it into the framebuffer. Mark the frame as */
/* decoded, but otherwise leave it in the playout buffer. */
struct pbuf_node *curr;
pbuf_validate(playout_buf);
curr = playout_buf->frst;
while (curr != NULL) {
/* WARNING: this one differs from video - we need to push audio immediately, because we do
* _not_ know the granularity of audio (typically 256 B for ALSA) which is only small fractal
* of frame time. The current RTP library isn't currently able to keep concurrently more frames.
*/
UNUSED(curr_time);
if (!curr->decoded // && tv_gt(curr_time, curr->playout_time)
) {
if (curr->mbit == 1) {
int ret = decode_func(curr->cdata, data);
curr->decoded = 1;
return ret;
}
}
curr = curr->nxt;
}
return 0;
}
void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay)
{
playout_buf->playout_delay = playout_delay;

View File

@@ -110,8 +110,6 @@ typedef int decode_frame_t(struct coded_data *cdata, void *decode_data);
*/
struct pbuf *pbuf_init(void);
void pbuf_insert(struct pbuf *playout_buf, rtp_packet *r);
int audio_pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time,
decode_frame_t decode_func, void *data);
int pbuf_is_empty(struct pbuf *playout_buf);
int pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time,
decode_frame_t decode_func, void *data);

View File

@@ -0,0 +1,156 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif // HAVE_CONFIG_H
#ifdef HAVE_NCURSES
#include <curses.h>
#include <stdlib.h>
#include <stdio.h>
#include "debug.h"
void usage(const char *progname);
int main(int argc, char *argv[]);
void sig_handler(int signal);
void usage(const char *progname) {
printf("Usage: %s <hostname> <port>\n", progname);
}
int fd = -1;// = socket(AF_INET6, SOCK_STREAM, 0);
void sig_handler(int signal) {
UNUSED(signal);
close(fd);
endwin();
exit(EXIT_SUCCESS);
}
static void *reading_thread(void *arg) {
UNUSED(arg);
ssize_t bytes;
char buf[1024];
while ((bytes = recv(fd, buf, sizeof(buf), 0)) > 0) {
write(1, buf, bytes);
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t reading_thread_id;
if(argc != 3) {
usage(argv[0]);
return EXIT_FAILURE;
}
signal(SIGINT, sig_handler);
signal(SIGPIPE, sig_handler);
const char *hostname = argv[1];
uint16_t port = atoi(argv[2]);
struct addrinfo hints, *res, *res0;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
const char *port_str = argv[2];
err = getaddrinfo(hostname, port_str, &hints, &res0);
if(err) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return EXIT_FAILURE;
}
char what[1024];
for (res = res0; res; res = res->ai_next) {
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd < 0) {
snprintf(what, 1024, "socket failed: %s", strerror(errno));
continue;
}
if(connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
fd = -1;
snprintf(what, 1024, "connect failed: %s:%d :%s", hostname, port, strerror(errno));
continue;
}
break; /* okay we got one */
}
freeaddrinfo(res0);
if(fd < 0 ) {
fprintf(stderr, "%s\n", what);
return EXIT_FAILURE;
}
initscr();
keypad(stdscr, TRUE);
scrollok(stdscr, TRUE);
pthread_create(&reading_thread_id, NULL, reading_thread, NULL);
while (1) {
char message[1024] = { '\0' };
int key = getch();
switch(key) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
snprintf(message, 1024, "capture.data %d",
key - '0');
break;
case 'q':
goto finish;
default:
printw("Unknown key: %d\n", key);
}
if(strlen(message) > 0) {
printw("Sent message: \"%s\"\n", message);
ssize_t total_written = 0;
do {
ssize_t ret = write(fd, message, strlen(message)+1 - total_written);
if(ret <= 0) {
perror("Error sending command");
goto finish;
}
total_written += ret;
} while(total_written < (int) strlen(message) + 1);
}
}
finish:
pthread_cancel(reading_thread_id);
pthread_join(reading_thread_id, NULL);
close(fd);
endwin();
return EXIT_SUCCESS;
}
#else // ! HAVE_NCURSES
#include <stdio.h>
int main () { fprintf(stderr, "Recompile with ncurses support!\n"); return 1; }
#endif // HAVE_NCURSES

View File

@@ -77,6 +77,7 @@
#include "video_capture/screen_osx.h"
#include "video_capture/screen_x11.h"
#include "video_capture/swmix.h"
#include "video_capture/switcher.h"
#include "video_capture/testcard.h"
#include "video_capture/testcard2.h"
#include "video_capture/v4l2.h"
@@ -103,6 +104,7 @@ struct vidcap_params {
char *name; ///< input name (capture alias in config file or complete config if not alias)
struct vidcap_params *next; /**< Pointer to next vidcap params. Used by aggregate capture drivers.
* Last device in list has @ref driver set to NULL. */
struct module *parent;
};
/// @brief This struct represents video capture state.
@@ -165,6 +167,15 @@ struct vidcap_device_api vidcap_device_table[] = {
MK_STATIC(vidcap_import_grab),
NULL
},
{
0,
NULL,
MK_STATIC(vidcap_switcher_probe),
MK_STATIC(vidcap_switcher_init),
MK_STATIC(vidcap_switcher_done),
MK_STATIC(vidcap_switcher_grab),
NULL
},
#if defined HAVE_RTSP
{
0,
@@ -457,7 +468,7 @@ vidcap_id_t vidcap_get_null_device_id(void)
* @retval <0 if initialization failed
* @retval >0 if initialization was successful but no state was returned (eg. only having shown help).
*/
int vidcap_init(struct module *parent, vidcap_id_t id, const struct vidcap_params *param,
int vidcap_init(struct module *parent, vidcap_id_t id, struct vidcap_params *param,
struct vidcap **state)
{
unsigned int i;
@@ -467,24 +478,28 @@ int vidcap_init(struct module *parent, vidcap_id_t id, const struct vidcap_param
struct vidcap *d =
(struct vidcap *)malloc(sizeof(struct vidcap));
d->magic = VIDCAP_MAGIC;
module_init_default(&d->mod);
d->mod.cls = MODULE_CLASS_CAPTURE;
module_register(&d->mod, parent);
param->parent = &d->mod;
d->state = vidcap_device_table[i].func_init(param);
d->index = i;
if (d->state == NULL) {
debug_msg
("Unable to start video capture device 0x%08lx\n",
id);
module_done(&d->mod);
free(d);
return -1;
}
if(d->state == &vidcap_init_noerr) {
module_done(&d->mod);
free(d);
return 1;
}
module_init_default(&d->mod);
d->mod.cls = MODULE_CLASS_CAPTURE;
module_register(&d->mod, parent);
int ret = capture_filter_init(&d->mod, param->requested_capture_filter,
&d->capture_filter);
if(ret < 0) {
@@ -682,6 +697,11 @@ const char *vidcap_params_get_name(const struct vidcap_params *params)
return params->name;
}
struct module *vidcap_params_get_parent(const struct vidcap_params *params)
{
return params->parent;
}
/**
* Creates deep copy of @ref vidcap_params structure.
*/

View File

@@ -110,6 +110,8 @@ struct vidcap_type {
//video_colour_mode_t colour_mode;
};
struct module;
/**
* @name Vidcap Parameters Handling Functions
* @{ */
@@ -125,6 +127,7 @@ const char *vidcap_params_get_driver(const struct vidcap_params *param
unsigned int vidcap_params_get_flags(const struct vidcap_params *params);
const char *vidcap_params_get_fmt(const struct vidcap_params *params);
const char *vidcap_params_get_name(const struct vidcap_params *params);
struct module *vidcap_params_get_parent(const struct vidcap_params *params);
void vidcap_params_set_device(struct vidcap_params *params, const char *config);
void vidcap_params_set_capture_filter(struct vidcap_params *params,
const char *req_capture_filter);
@@ -141,7 +144,7 @@ struct module;
struct vidcap;
int vidcap_init(struct module *parent, vidcap_id_t id,
const struct vidcap_params *param, struct vidcap **);
struct vidcap_params *param, struct vidcap **);
void vidcap_done(struct vidcap *state);
struct video_frame *vidcap_grab(struct vidcap *state, struct audio_frame **audio);

View File

@@ -135,6 +135,7 @@ struct vidcap_decklink_state {
unsigned int autodetect_mode:1;
BMDVideoConnection connection;
int audio_consumer_levels; ///< 0 false, 1 true, -1 default
struct timeval t0;
};
@@ -393,7 +394,7 @@ decklink_help()
HRESULT result;
printf("\nDecklink options:\n");
printf("\t-t decklink[:<device_index(indices)>[:<mode>:<colorspace>[:3D][:timecode][:connection=<input>]]\n");
printf("\t-t decklink[:<device_index(indices)>[:<mode>:<colorspace>[:3D][:timecode][:connection=<input>]][:audioConsumerLevels={true|false}]\\n");
printf("\t\t(You can omit device index, mode and color space provided that your cards supports format autodetection.)\n");
// Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
@@ -502,6 +503,11 @@ decklink_help()
printf("timecode\n");
printf("\tTry to synchronize inputs based on timecode (for multiple inputs, eg. tiled 4K)\n");
printf("audioConsumerLevels\n");
printf("\tIf set true the analog audio levels are set to maximum gain on audio input.\n");
printf("\tIf set false the selected analog input gain levels are used.\n");
printf("\n");
return 1;
}
@@ -600,6 +606,14 @@ settings_init(void *state, char *fmt)
fprintf(stderr, "[DeckLink] Unrecognized connection %s.\n", connection);
return 0;
}
} else if(strncasecmp(tmp, "audioConsumerLevels=",
strlen("audioConsumerLevels=")) == 0) {
char *levels = tmp + strlen("audioConsumerLevels=");
if (strcasecmp(levels, "false") == 0) {
s->audio_consumer_levels = 0;
} else {
s->audio_consumer_levels = 1;
}
} else {
fprintf(stderr, "[DeckLink] Warning, unrecognized trailing options in init string: %s", tmp);
}
@@ -791,6 +805,7 @@ vidcap_decklink_init(const struct vidcap_params *params)
s->autodetect_mode = FALSE;
s->connection = (BMDVideoConnection) 0;
s->flags = 0;
s->audio_consumer_levels = -1;
// SET UP device and mode
char *tmp_fmt = strdup(vidcap_params_get_fmt(params));
@@ -1039,6 +1054,13 @@ vidcap_decklink_init(const struct vidcap_params *params)
"Only 1, 2, 8 or 16 are poosible.", audio_capture_channels);
goto error;
}
if (s->audio_consumer_levels != -1) {
result = deckLinkConfiguration->SetFlag(bmdDeckLinkConfigAnalogAudioConsumerLevels,
s->audio_consumer_levels == 1 ? true : false);
if(result != S_OK) {
fprintf(stderr, "[DeckLink capture] Unable set input audio consumer levels.\n");
}
}
deckLinkInput->EnableAudioInput(
bmdAudioSampleRate48kHz,
bmdAudioSampleType16bitInteger,

View File

@@ -797,7 +797,7 @@ void setup_codecs_and_controls_from_sdp(const char *sdp_filename, void *state) {
if(fp == 0){
printf("unable to open asset %s", sdp_filename);
fclose(fp);
return -1;
return;
}
fseek(fp, 0, SEEK_END);
unsigned long fileSize = ftell(fp);
@@ -808,7 +808,7 @@ void setup_codecs_and_controls_from_sdp(const char *sdp_filename, void *state) {
if(readResult != fileSize){
printf("something bad happens, read result != file size");
return -1;
return;
}
buffer[fileSize] = '\0';

View File

@@ -57,8 +57,6 @@
#include <pthread.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <Carbon/Carbon.h>
/* prototypes of functions defined in this module */

View File

@@ -0,0 +1,190 @@
/**
* @file video_capture/switcher.c
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2014 CESNET z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "host.h"
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#include "debug.h"
#include "video.h"
#include "video_capture.h"
#include "tv.h"
#include "video_capture/switcher.h"
#include "audio/audio.h"
#include "module.h"
#include <stdio.h>
#include <stdlib.h>
/* prototypes of functions defined in this module */
static void show_help(void);
static void show_help()
{
printf("switcher capture\n");
printf("Usage\n");
printf("\t-t switcher -t <dev1_config> -t <dev2_config> ....]\n");
printf("\t\twhere devn_config is a configuration of device to be switched\n");
}
struct vidcap_switcher_state {
struct module mod;
struct vidcap **devices;
int devices_cnt;
int selected_device;
};
struct vidcap_type *
vidcap_switcher_probe(void)
{
struct vidcap_type* vt;
vt = (struct vidcap_type *) malloc(sizeof(struct vidcap_type));
if (vt != NULL) {
vt->id = 0x1D3E1956;
vt->name = "switcher";
vt->description = "Video switcher pseudodevice";
}
return vt;
}
void *
vidcap_switcher_init(const struct vidcap_params *params)
{
struct vidcap_switcher_state *s;
int i;
printf("vidcap_switcher_init\n");
s = (struct vidcap_switcher_state *) calloc(1, sizeof(struct vidcap_switcher_state));
if(s == NULL) {
printf("Unable to allocate switcher capture state\n");
return NULL;
}
if(vidcap_params_get_fmt(params) && strcmp(vidcap_params_get_fmt(params), "") != 0) {
show_help();
return &vidcap_init_noerr;
}
s->devices_cnt = 0;
const struct vidcap_params *tmp = params;
while((tmp = vidcap_params_get_next(tmp))) {
if (vidcap_params_get_driver(tmp) != NULL)
s->devices_cnt++;
else
break;
}
s->devices = calloc(s->devices_cnt, sizeof(struct vidcap *));
i = 0;
tmp = params;
for (int i = 0; i < s->devices_cnt; ++i) {
tmp = vidcap_params_get_next(tmp);
int ret = initialize_video_capture(NULL, tmp, &s->devices[i]);
if(ret != 0) {
fprintf(stderr, "[switcher] Unable to initialize device %d (%s:%s).\n",
i, vidcap_params_get_driver(tmp),
vidcap_params_get_fmt(tmp));
goto error;
}
}
module_init_default(&s->mod);
s->mod.cls = MODULE_CLASS_DATA;
module_register(&s->mod, vidcap_params_get_parent(params));
return s;
error:
if(s->devices) {
int i;
for (i = 0u; i < s->devices_cnt; ++i) {
if(s->devices[i]) {
vidcap_done(s->devices[i]);
}
}
}
free(s);
return NULL;
}
void
vidcap_switcher_done(void *state)
{
struct vidcap_switcher_state *s = (struct vidcap_switcher_state *) state;
assert(s != NULL);
if (s != NULL) {
int i;
for (i = 0; i < s->devices_cnt; ++i) {
vidcap_done(s->devices[i]);
}
}
module_done(&s->mod);
free(s);
}
struct video_frame *
vidcap_switcher_grab(void *state, struct audio_frame **audio)
{
struct vidcap_switcher_state *s = (struct vidcap_switcher_state *) state;
struct audio_frame *audio_frame = NULL;
struct video_frame *frame = NULL;
struct message *msg;
while ((msg = check_message(&s->mod))) {
struct msg_universal *msg_univ = (struct msg_universal *) msg;
int new_selected_device = atoi(msg_univ->text);
if (new_selected_device >= 0 && new_selected_device < s->devices_cnt)
s->selected_device = new_selected_device;
free_message(msg);
}
frame = vidcap_grab(s->devices[s->selected_device], &audio_frame);
*audio = audio_frame;;
return frame;
}

View File

@@ -0,0 +1,42 @@
/**
* @file video_capture/switcher.h
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2014 CESNET z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
struct vidcap_type *vidcap_switcher_probe(void);
void *vidcap_switcher_init(const struct vidcap_params *params);
void vidcap_switcher_done(void *state);
struct video_frame *vidcap_switcher_grab(void *state, struct audio_frame **audio);

View File

@@ -78,18 +78,17 @@ void print_fps(int fd, struct v4l2_frmivalenum *param);
#define DEFAULT_DEVICE "/dev/video0"
#define BUF_COUNT 2
#define DEFAULT_BUF_COUNT 2
#define MAX_BUF_COUNT 30
struct vidcap_v4l2_state {
struct video_frame *frame;
struct tile *tile;
struct video_desc desc;
int fd;
struct {
void *start;
size_t length;
} buffers[BUF_COUNT];
struct v4l2_buffer v4l2_dequeued_buffer;
} buffers[MAX_BUF_COUNT];
bool conversion_needed;
struct v4lconvert_data *convert;
@@ -135,9 +134,10 @@ static void show_help()
{
printf("V4L2 capture\n");
printf("Usage\n");
printf("\t-t v4l2[:<dev>[:<pixel_fmt>:[<width>:<height>[:<tpf>]]]]\n");
printf("\t-t v4l2[:dev=<dev>][:fmt=<pixel_fmt>][:size=<width>x<height>][:tpf=<tpf>][:buffers=<bufcnt>]\n");
printf("\t\tuse device <dev> for grab (default: %s)\n", DEFAULT_DEVICE);
printf("\t\t<tpf> - time per frame in format <numerator>/<denominator>\n");
printf("\t\t<bufcnt> - number of capture buffers to be used (default: %d)\n", DEFAULT_BUF_COUNT);
for (int i = 0; i < 64; ++i) {
char name[32];
@@ -254,6 +254,7 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
height = 0;
uint32_t numerator = 0,
denominator = 0;
int buffer_count = DEFAULT_BUF_COUNT;
printf("vidcap_v4l2_init\n");
@@ -276,47 +277,47 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
char *init_fmt = tmp;
char *save_ptr = NULL;
char *item;
int i = 0;
while((item = strtok_r(init_fmt, ":", &save_ptr))) {
int len;
switch (i) {
case 0:
dev_name = item;
break;
case 1:
{
if (strncmp(item, "dev=",
strlen("dev=")) == 0) {
dev_name = item + strlen("dev=");
} else if (strncmp(item, "fmt=",
strlen("fmt=")) == 0) {
char *fmt = item + strlen("fmt=");
union {
uint32_t fourcc;
char str[4];
} str_to_uint;
len = 4;
if(strlen(item) < 4) len = strlen(item);
int len = 4;
if(strlen(fmt) < 4) len = strlen(fmt);
memset(str_to_uint.str, 0, 4);
memcpy(str_to_uint.str, item, len);
memcpy(str_to_uint.str, fmt, len);
pixelformat = str_to_uint.fourcc;
}
break;
case 2:
width = atoi(item);
break;
case 3:
height = atoi(item);
break;
case 4:
} else if (strncmp(item, "size=",
strlen("size=")) == 0) {
if(strchr(item, 'x')) {
width = atoi(item + strlen("size="));
height = atoi(strchr(item, 'x') + 1);
}
} else if (strncmp(item, "tpf=",
strlen("tpf=")) == 0) {
if(strchr(item, '/')) {
numerator = atoi(item);
numerator = atoi(item + strlen("tpf="));
denominator = atoi(strchr(item, '/') + 1);
}
break;
} else if (strncmp(item, "buffers=",
strlen("buffers=")) == 0) {
buffer_count = atoi(item + strlen("buffers="));
assert (buffer_count <= MAX_BUF_COUNT);
} else {
fprintf(stderr, "[V4L2] Invalid configuration argument: %s\n",
item);
return NULL;
}
init_fmt = NULL;
++i;
}
}
s->frame = NULL;
s->fd = open(dev_name, O_RDWR);
if(s->fd == -1) {
@@ -368,31 +369,32 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
goto error_fd;
}
if(pixelformat) {
if (pixelformat) {
fmt.fmt.pix.pixelformat = pixelformat;
}
if(width != 0 && height != 0) {
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
}
fmt.fmt.pix.field = V4L2_FIELD_ANY;
fmt.fmt.pix.bytesperline = 0;
if(width != 0 && height != 0) {
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
}
fmt.fmt.pix.field = V4L2_FIELD_ANY;
fmt.fmt.pix.bytesperline = 0;
if(ioctl(s->fd, VIDIOC_S_FMT, &fmt) != 0) {
perror("[V4L2] Unable to set video formant");
goto error_fd;
}
if(numerator != 0 && denominator != 0) {
stream_params.parm.capture.timeperframe.numerator = numerator;
stream_params.parm.capture.timeperframe.denominator = denominator;
if(ioctl(s->fd, VIDIOC_S_PARM, &stream_params) != 0) {
perror("[V4L2] Unable to set stream params");
if(ioctl(s->fd, VIDIOC_S_FMT, &fmt) != 0) {
perror("[V4L2] Unable to set video formant");
goto error_fd;
}
if(numerator != 0 && denominator != 0) {
stream_params.parm.capture.timeperframe.numerator = numerator;
stream_params.parm.capture.timeperframe.denominator = denominator;
if(ioctl(s->fd, VIDIOC_S_PARM, &stream_params) != 0) {
perror("[V4L2] Unable to set stream params");
goto error_fd;
}
}
}
memcpy(&s->src_fmt, &fmt, sizeof(fmt));
@@ -410,49 +412,48 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
goto error_fd;
}
s->frame = vf_alloc(1);
s->tile = vf_get_tile(s->frame, 0);
s->desc.tile_count = 1;
s->conversion_needed = false;
switch(fmt.fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUYV:
s->frame->color_spec = YUYV;
s->desc.color_spec = YUYV;
break;
case V4L2_PIX_FMT_UYVY:
s->frame->color_spec = UYVY;
s->desc.color_spec = UYVY;
break;
case V4L2_PIX_FMT_RGB24:
s->frame->color_spec = RGB;
s->desc.color_spec = RGB;
break;
case V4L2_PIX_FMT_RGB32:
s->frame->color_spec = RGBA;
s->desc.color_spec = RGBA;
break;
case V4L2_PIX_FMT_MJPEG:
s->frame->color_spec = MJPG;
s->desc.color_spec = MJPG;
break;
case V4L2_PIX_FMT_H264:
s->frame->color_spec = H264;
s->desc.color_spec = H264;
break;
default:
s->conversion_needed = true;
s->dst_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
s->frame->color_spec = RGB;
s->desc.color_spec = RGB;
break;
}
switch(fmt.fmt.pix.field) {
case V4L2_FIELD_NONE:
s->frame->interlacing = PROGRESSIVE;
s->desc.interlacing = PROGRESSIVE;
break;
case V4L2_FIELD_TOP:
s->frame->interlacing = UPPER_FIELD_FIRST;
s->desc.interlacing = UPPER_FIELD_FIRST;
break;
case V4L2_FIELD_BOTTOM:
s->frame->interlacing = LOWER_FIELD_FIRST;
s->desc.interlacing = LOWER_FIELD_FIRST;
break;
case V4L2_FIELD_INTERLACED:
s->frame->interlacing = INTERLACED_MERGED;
s->desc.interlacing = INTERLACED_MERGED;
break;
case V4L2_FIELD_SEQ_TB:
case V4L2_FIELD_SEQ_BT:
@@ -461,18 +462,14 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
case V4L2_FIELD_INTERLACED_BT:
default:
fprintf(stderr, "[V4L2] Unsupported interlacing format reported from driver.\n");
goto free_frame;
goto error_fd;
}
s->frame->fps = (double) stream_params.parm.capture.timeperframe.denominator /
s->desc.fps = (double) stream_params.parm.capture.timeperframe.denominator /
stream_params.parm.capture.timeperframe.numerator;
s->tile->width = fmt.fmt.pix.width;
s->tile->height = fmt.fmt.pix.height;
s->desc.width = fmt.fmt.pix.width;
s->desc.height = fmt.fmt.pix.height;
if(s->conversion_needed) {
s->tile->data_len = vc_get_linesize(s->tile->width, s->frame->color_spec) *
s->tile->height;
s->tile->data = malloc(s->tile->data_len);
s->frame->data_deleter = vf_data_deleter;
s->convert = v4lconvert_create(s->fd);
} else {
s->convert = NULL;
@@ -483,21 +480,21 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = BUF_COUNT;
reqbuf.count = buffer_count;
if (ioctl (s->fd, VIDIOC_REQBUFS, &reqbuf) != 0) {
if (errno == EINVAL)
printf("Video capturing or mmap-streaming is not supported\n");
else
perror("VIDIOC_REQBUFS");
goto free_frame;
goto error_fd;
}
if (reqbuf.count < 2) {
/* You may need to free the buffers here. */
printf("Not enough buffer memory\n");
goto free_frame;
goto error_fd;
}
for (unsigned int i = 0; i < reqbuf.count; i++) {
@@ -509,7 +506,7 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
if (-1 == ioctl (s->fd, VIDIOC_QUERYBUF, &buf)) {
perror("VIDIOC_QUERYBUF");
goto free_frame;
goto error_fd;
}
s->buffers[i].length = buf.length; /* remember for munmap() */
@@ -523,24 +520,20 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
/* If you do not exit here you should unmap() and free()
the buffers mapped so far. */
perror("mmap");
goto free_frame;
goto error_fd;
}
buf.flags = 0;
if (i < reqbuf.count - 1) {
if(ioctl(s->fd, VIDIOC_QBUF, &buf) != 0) {
perror("Unable to enqueue buffer");
goto free_frame;
}
} else {
memcpy(&s->v4l2_dequeued_buffer, &buf, sizeof(buf));
if(ioctl(s->fd, VIDIOC_QBUF, &buf) != 0) {
perror("Unable to enqueue buffer");
goto error_fd;
}
}
if(ioctl(s->fd, VIDIOC_STREAMON, &reqbuf.type) != 0) {
perror("Unable to start stream");
goto free_frame;
goto error_fd;
};
gettimeofday(&s->t0, NULL);
@@ -550,8 +543,6 @@ void * vidcap_v4l2_init(const struct vidcap_params *params)
return s;
free_frame:
vf_free(s->frame);
error_fd:
close(s->fd);
free(s);
@@ -569,8 +560,6 @@ void vidcap_v4l2_done(void *state)
close(s->fd);
vf_free(s->frame);
if(s->conversion_needed) {
v4lconvert_destroy(s->convert);
}
@@ -578,16 +567,33 @@ void vidcap_v4l2_done(void *state)
free(s);
}
struct v4l2_dispose_deq_buffer_data {
int fd;
struct v4l2_buffer buf;
};
static void vidcap_v4l2_dispose_video_frame(struct video_frame *frame) {
struct v4l2_dispose_deq_buffer_data *data =
(struct v4l2_dispose_deq_buffer_data *) frame->dispose_udata;
if (data) {
if (ioctl(data->fd, VIDIOC_QBUF, &data->buf) != 0) {
perror("Unable to enqueue buffer");
};
free(data);
} else {
free(frame->tiles[0].data);
}
vf_free(frame);
}
struct video_frame * vidcap_v4l2_grab(void *state, struct audio_frame **audio)
{
struct vidcap_v4l2_state *s = (struct vidcap_v4l2_state *) state;
struct video_frame *out;
*audio = NULL;
if (ioctl(s->fd, VIDIOC_QBUF, &s->v4l2_dequeued_buffer) != 0) {
perror("Unable to enqueue buffer");
};
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -595,27 +601,42 @@ struct video_frame * vidcap_v4l2_grab(void *state, struct audio_frame **audio)
if(ioctl(s->fd, VIDIOC_DQBUF, &buf) != 0) {
perror("Unable to dequeue buffer");
return NULL;
};
memcpy(&s->v4l2_dequeued_buffer, &buf, sizeof(buf));
out = vf_alloc_desc(s->desc);
out->dispose = vidcap_v4l2_dispose_video_frame;
if(!s->conversion_needed) {
s->tile->data = s->buffers[buf.index].start;
s->tile->data_len = buf.bytesused;
struct v4l2_dispose_deq_buffer_data *frame_data =
malloc(sizeof(struct v4l2_dispose_deq_buffer_data));
frame_data->fd = s->fd;
memcpy(&frame_data->buf, &buf, sizeof(buf));
out->tiles[0].data = s->buffers[frame_data->buf.index].start;
out->tiles[0].data_len = frame_data->buf.bytesused;
out->dispose_udata = frame_data;
} else {
out->dispose_udata = NULL;
out->tiles[0].data = (char *) malloc(out->tiles[0].data_len);
int ret = v4lconvert_convert(s->convert,
&s->src_fmt, /* in */
&s->dst_fmt, /* in */
s->buffers[buf.index].start,
buf.bytesused,
(unsigned char *) s->tile->data,
s->tile->data_len);
(unsigned char *) out->tiles[0].data,
out->tiles[0].data_len);
// we do not need the driver buffer any more
if (ioctl(s->fd, VIDIOC_QBUF, &buf) != 0) {
perror("Unable to enqueue buffer");
};
if(ret == -1) {
fprintf(stderr, "Error converting video.\n");
return NULL;
}
s->tile->data_len = ret;
out->tiles[0].data_len = ret;
}
s->frames++;
@@ -631,6 +652,6 @@ struct video_frame * vidcap_v4l2_grab(void *state, struct audio_frame **audio)
}
return s->frame;
return out;
}

View File

@@ -149,13 +149,13 @@ static int parse_fmt(struct state_video_compress_libav *s, char *fmt);
static void cleanup(struct state_video_compress_libav *s);
static void libavcodec_vid_enc_frame_dispose(struct video_frame *frame) {
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
#if LIBAVCODEC_VERSION_MAJOR >= 54
AVPacket *pkt = (AVPacket *) frame->dispose_udata;
av_free_packet(pkt);
free(pkt);
#else
free(frame->tiles[0].data);
#endif // HAVE_AVCODEC_ENCODE_VIDEO2
#endif // LIBAVCODEC_VERSION_MAJOR >= 54
vf_free(frame);
}
@@ -583,7 +583,7 @@ struct video_frame *libavcodec_compress_tile(struct module *mod, struct video_fr
struct state_video_compress_libav *s = (struct state_video_compress_libav *) mod->priv_data;
static int frame_seq = 0;
int ret;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
#if LIBAVCODEC_VERSION_MAJOR >= 54
int got_output;
#endif
unsigned char *decoded;
@@ -601,7 +601,7 @@ struct video_frame *libavcodec_compress_tile(struct module *mod, struct video_fr
struct video_frame *out = vf_alloc_desc(s->compressed_desc);
out->dispose = libavcodec_vid_enc_frame_dispose;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
#if LIBAVCODEC_VERSION_MAJOR >= 54
AVPacket *pkt = (AVPacket *) malloc(sizeof(AVPacket));
av_init_packet(pkt);
pkt->data = NULL;
@@ -610,7 +610,7 @@ struct video_frame *libavcodec_compress_tile(struct module *mod, struct video_fr
#else
out->tiles[0].data = malloc(s->compressed_desc.width *
s->compressed_desc.height * 4);
#endif // HAVE_AVCODEC_ENCODE_VIDEO2
#endif // LIBAVCODEC_VERSION_MAJOR >= 54
s->in_frame->pts = frame_seq++;
@@ -657,7 +657,7 @@ struct video_frame *libavcodec_compress_tile(struct module *mod, struct video_fr
}
}
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
#if LIBAVCODEC_VERSION_MAJOR >= 54
/* encode the image */
ret = avcodec_encode_video2(s->codec_ctx, pkt,
s->in_frame, &got_output);
@@ -689,7 +689,7 @@ struct video_frame *libavcodec_compress_tile(struct module *mod, struct video_fr
} else {
goto error;
}
#endif // HAVE_AVCODEC_ENCODE_VIDEO2
#endif // LIBAVCODEC_VERSION_MAJOR >= 54
platform_spin_unlock(&s->spin);

View File

@@ -280,8 +280,8 @@ static void show_help(void)
HRESULT result;
printf("Decklink (output) options:\n");
printf("\t-d decklink:<device_number(s)>[:timecode][:3G|:dual-link][:3D[:HDMI3DPacking=<packing>]][:fast]\n");
printf("\t\tcoma-separated numbers of output devices\n");
printf("\t-d decklink:<device_number(s)>[:timecode][:3G|:dual-link][:3D[:HDMI3DPacking=<packing>]][:fast][:audioConsumerLevels={true|false}]\n");
printf("\t\t<device_number(s)> is coma-separated indices of output devices\n");
// Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
#ifdef WIN32
result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
@@ -352,6 +352,8 @@ static void show_help(void)
printf("Fast mode has lower latency at the expense of incorrect displaying (frame rewriting).\n");
printf("\n");
printf("audioConsumerLevels if set to true sets audio analog level to maximum attenuation on audio output.\n");
printf("\n");
}
@@ -734,6 +736,7 @@ void *display_decklink_init(char *fmt, unsigned int flags)
// for Decklink Studio which has switchable XLR - analog 3 and 4 or AES/EBU 3,4 and 5,6
BMDAudioOutputAnalogAESSwitch audioConnection = (BMDAudioOutputAnalogAESSwitch) 0;
BMDVideo3DPackingFormat HDMI3DPacking = (BMDVideo3DPackingFormat) 0;
int audio_consumer_levels = -1;
#ifdef WIN32
@@ -835,6 +838,12 @@ void *display_decklink_init(char *fmt, unsigned int flags)
}
} else if(strcasecmp(ptr, "fast") == 0) {
s->fast = true;
} else if(strncasecmp(ptr, "audioConsumerLevels=", strlen("audioConsumerLevels=")) == 0) {
if (strcasecmp(ptr + strlen("audioConsumerLevels="), "false") == 0) {
audio_consumer_levels = 0;
} else {
audio_consumer_levels = 1;
}
} else {
fprintf(stderr, "[DeckLink] Warning: unknown options in config string.\n");
}
@@ -986,17 +995,25 @@ void *display_decklink_init(char *fmt, unsigned int flags)
* .... one exception is a card that has switchable cables between AES/EBU and analog. (But this applies only for channels 3 and above.)
*/
if (audioConnection != 0) { // not embedded
HRESULT res = deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioOutputAESAnalogSwitch,
result = deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioOutputAESAnalogSwitch,
audioConnection);
if(res == S_OK) { // has switchable channels
if(result == S_OK) { // has switchable channels
printf("[Decklink playback] Card with switchable audio channels detected. Switched to correct format.\n");
} else if(res == E_NOTIMPL) {
} else if(result == E_NOTIMPL) {
// normal case - without switchable channels
} else {
fprintf(stderr, "[Decklink playback] Unable to switch audio output for channels 3 or above although \n"
"card shall support it. Check if it is ok. Continuing anyway.\n");
}
}
if (audio_consumer_levels != -1) {
result = deckLinkConfiguration->SetFlag(bmdDeckLinkConfigAnalogAudioConsumerLevels,
audio_consumer_levels == 1 ? true : false);
if(result != S_OK) {
fprintf(stderr, "[DeckLink display] Unable set output audio consumer levels.\n");
}
}
}
s->state[i].delegate = new PlaybackDelegate();
@@ -1159,6 +1176,7 @@ void display_decklink_put_audio_frame(void *state, struct audio_frame *frame)
tmp_frame.max_size = sampleFrameCount * s->output_audio_channel_count
* frame->bps;
tmp_frame.data = (char *) malloc(tmp_frame.max_size);
memcpy(tmp_frame.data, frame->data, frame->data_len);
audio_frame_multiply_channel(&tmp_frame,
s->output_audio_channel_count);

View File

@@ -91,8 +91,8 @@
#include "video_display/splashscreen.h"
#include "tv.h"
#define MAGIC_GL DISPLAY_GL_ID
#define WIN_NAME "Ultragrid - OpenGL Display"
#define MAGIC_GL DISPLAY_GL_ID
#define DEFAULT_WIN_NAME "Ultragrid - OpenGL Display"
#define STRINGIFY(A) #A
@@ -264,6 +264,7 @@ static void gl_load_splashscreen(struct state_gl *s)
gl_reconfigure_screen(s);
for (int i = 0; i < 2; ++i) {
const char *data = splash_data;
memset(s->buffers[i], 0, s->tile->data_len);
for (unsigned int y = 0; y < splash_height; ++y) {
char *line = s->buffers[i];
@@ -274,7 +275,7 @@ static void gl_load_splashscreen(struct state_gl *s)
(s->tile->width - splash_width)/2,
s->frame->color_spec);
for (unsigned int x = 0; x < splash_width; ++x) {
HEADER_PIXEL(splash_data,line);
HEADER_PIXEL(data,line);
line += 4;
}
}
@@ -383,7 +384,7 @@ void * display_gl_init(char *fmt, unsigned int flags) {
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
#endif
glutIdleFunc(glut_idle_callback);
s->window = glutCreateWindow(WIN_NAME);
s->window = glutCreateWindow(window_title != NULL ? window_title : DEFAULT_WIN_NAME);
glutSetCursor(s->show_cursor ? GLUT_CURSOR_CROSSHAIR : GLUT_CURSOR_NONE);
//glutHideWindow();
glutKeyboardFunc(glut_key_callback);
@@ -489,13 +490,15 @@ int display_gl_reconfigure(void *state, struct video_desc desc)
static void glut_resize_window(struct state_gl *s)
{
if (!s->fs) {
if (s->fs) {
glutReshapeWindow(glutGet(GLUT_SCREEN_WIDTH),
glutGet(GLUT_SCREEN_HEIGHT));
glutFullScreen();
} else {
glutReshapeWindow(s->window_size_factor *
s->tile->height * s->aspect,
s->window_size_factor *
s->tile->height);
} else {
glutFullScreen();
}
}
@@ -877,7 +880,7 @@ static void gl_resize(int width,int height)
// redraw last frame
gl_render(gl);
gl_draw(gl->aspect);
glutPostRedisplay();
glutSwapBuffers();
}
static void gl_bind_texture(void *arg)

View File

@@ -168,10 +168,11 @@ static void loadSplashscreen(struct state_sdl *s) {
#endif
// load splash data
const char *data = splash_data;
for (y_coord = 0; y_coord < splash_height; y_coord++) {
for (x_coord = 0; x_coord < splash_width; x_coord++) {
HEADER_PIXEL(splash_data,pixel);
HEADER_PIXEL(data,pixel);
Uint32 color = SDL_MapRGB(image->format, pixel[0], pixel[1], pixel[2]);
switch(image->format->BytesPerPixel) {
@@ -472,7 +473,11 @@ int display_sdl_reconfigure(void *state, struct video_desc desc)
x_res_y);
return FALSE;
}
SDL_WM_SetCaption("Ultragrid - SDL Display", "Ultragrid");
if (window_title) {
SDL_WM_SetCaption(window_title, window_title);
} else {
SDL_WM_SetCaption("Ultragrid - SDL Display", "Ultragrid");
}
SDL_ShowCursor(SDL_DISABLE);

View File

@@ -1,7 +1,7 @@
/* GIMP header image file format (RGB) */
static unsigned int splash_width = 339;
static unsigned int splash_height = 195;
static const unsigned int splash_width = 339;
static const unsigned int splash_height = 195;
/* Call this macro repeatedly. After each use, the pixel data can be extracted */
@@ -11,7 +11,7 @@ pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \
pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \
data += 4; \
}
static char *splash_data =
static const char * const splash_data =
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

View File

@@ -183,6 +183,8 @@ void *video_rxtx::sender_loop() {
if (!m_paused) {
send_frame(tx_frame);
} else {
VIDEO_FRAME_DISPOSE(tx_frame);
}
if (dynamic_cast<rtp_video_rxtx *>(this)) {