-
-
Save anonymous/43c21e8c236bf4c7efa2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/configure b/configure | |
index 45e751f..c616062 100755 | |
--- a/configure | |
+++ b/configure | |
@@ -2769,6 +2769,8 @@ gdigrab_indev_select="bmp_decoder" | |
iec61883_indev_deps="libiec61883" | |
jack_indev_deps="jack_jack_h" | |
jack_indev_deps_any="sem_timedwait dispatch_dispatch_h" | |
+jack_outdev_deps="jack_jack_h" | |
+jack_outdev_deps_any="sem_timedwait dispatch_dispatch_h" | |
lavfi_indev_deps="avfilter" | |
libcdio_indev_deps="libcdio" | |
libdc1394_indev_deps="libdc1394" | |
@@ -5720,7 +5722,7 @@ check_header soundcard.h | |
enabled_any alsa_indev alsa_outdev && | |
check_lib2 alsa/asoundlib.h snd_pcm_htimestamp -lasound | |
-enabled jack_indev && check_lib2 jack/jack.h jack_client_open -ljack && | |
+enabled jack_indev jack_outdev && check_lib2 jack/jack.h jack_client_open -ljack && | |
check_func jack_port_get_latency_range -ljack | |
enabled_any sndio_indev sndio_outdev && check_lib2 sndio.h sio_open -lsndio | |
diff --git a/libavdevice/Makefile b/libavdevice/Makefile | |
index 8394e87..329b2c0 100644 | |
--- a/libavdevice/Makefile | |
+++ b/libavdevice/Makefile | |
@@ -27,7 +27,8 @@ OBJS-$(CONFIG_FBDEV_OUTDEV) += fbdev_enc.o \ | |
fbdev_common.o | |
OBJS-$(CONFIG_GDIGRAB_INDEV) += gdigrab.o | |
OBJS-$(CONFIG_IEC61883_INDEV) += iec61883.o | |
-OBJS-$(CONFIG_JACK_INDEV) += jack.o timefilter.o | |
+OBJS-$(CONFIG_JACK_INDEV) += jack_dec.o jack.o timefilter.o | |
+OBJS-$(CONFIG_JACK_OUTDEV) += jack_enc.o jack.o | |
OBJS-$(CONFIG_LAVFI_INDEV) += lavfi.o | |
OBJS-$(CONFIG_OPENAL_INDEV) += openal-dec.o | |
OBJS-$(CONFIG_OPENGL_OUTDEV) += opengl_enc.o | |
diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c | |
index 26aecf2..007e891 100644 | |
--- a/libavdevice/alldevices.c | |
+++ b/libavdevice/alldevices.c | |
@@ -56,7 +56,7 @@ void avdevice_register_all(void) | |
REGISTER_INOUTDEV(FBDEV, fbdev); | |
REGISTER_INDEV (GDIGRAB, gdigrab); | |
REGISTER_INDEV (IEC61883, iec61883); | |
- REGISTER_INDEV (JACK, jack); | |
+ REGISTER_INOUTDEV(JACK, jack); | |
REGISTER_INDEV (LAVFI, lavfi); | |
REGISTER_INDEV (OPENAL, openal); | |
REGISTER_OUTDEV (OPENGL, opengl); | |
diff --git a/libavdevice/jack.c b/libavdevice/jack.c | |
index 5455484..07048c3 100644 | |
--- a/libavdevice/jack.c | |
+++ b/libavdevice/jack.c | |
@@ -1,8 +1,6 @@ | |
/* | |
- * JACK Audio Connection Kit input device | |
* Copyright (c) 2009 Samalyse | |
- * Author: Olivier Guilyardi <olivier samalyse com> | |
- * | |
+ * Copyright (c) 2016 Josh de Kock | |
* This file is part of FFmpeg. | |
* | |
* FFmpeg is free software; you can redistribute it and/or | |
@@ -20,7 +18,6 @@ | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
-#include "config.h" | |
#include <semaphore.h> | |
#include <jack/jack.h> | |
@@ -35,128 +32,7 @@ | |
#include "timefilter.h" | |
#include "avdevice.h" | |
-#if HAVE_DISPATCH_DISPATCH_H | |
-#include <dispatch/dispatch.h> | |
-#define sem_t dispatch_semaphore_t | |
-#define sem_init(psem,x,val) *psem = dispatch_semaphore_create(val) | |
-#define sem_post(psem) dispatch_semaphore_signal(*psem) | |
-#define sem_wait(psem) dispatch_semaphore_wait(*psem, DISPATCH_TIME_FOREVER) | |
-#define sem_timedwait(psem, val) dispatch_semaphore_wait(*psem, dispatch_walltime(val, 0)) | |
-#define sem_destroy(psem) dispatch_release(*psem) | |
-#endif | |
- | |
-/** | |
- * Size of the internal FIFO buffers as a number of audio packets | |
- */ | |
-#define FIFO_PACKETS_NUM 16 | |
- | |
-typedef struct JackData { | |
- AVClass *class; | |
- jack_client_t * client; | |
- int activated; | |
- sem_t packet_count; | |
- jack_nframes_t sample_rate; | |
- jack_nframes_t buffer_size; | |
- jack_port_t ** ports; | |
- int nports; | |
- TimeFilter * timefilter; | |
- AVFifoBuffer * new_pkts; | |
- AVFifoBuffer * filled_pkts; | |
- int pkt_xrun; | |
- int jack_xrun; | |
-} JackData; | |
- | |
-static int process_callback(jack_nframes_t nframes, void *arg) | |
-{ | |
- /* Warning: this function runs in realtime. One mustn't allocate memory here | |
- * or do any other thing that could block. */ | |
- | |
- int i, j; | |
- JackData *self = arg; | |
- float * buffer; | |
- jack_nframes_t latency, cycle_delay; | |
- AVPacket pkt; | |
- float *pkt_data; | |
- double cycle_time; | |
- | |
- if (!self->client) | |
- return 0; | |
- | |
- /* The approximate delay since the hardware interrupt as a number of frames */ | |
- cycle_delay = jack_frames_since_cycle_start(self->client); | |
- | |
- /* Retrieve filtered cycle time */ | |
- cycle_time = ff_timefilter_update(self->timefilter, | |
- av_gettime() / 1000000.0 - (double) cycle_delay / self->sample_rate, | |
- self->buffer_size); | |
- | |
- /* Check if an empty packet is available, and if there's enough space to send it back once filled */ | |
- if ((av_fifo_size(self->new_pkts) < sizeof(pkt)) || (av_fifo_space(self->filled_pkts) < sizeof(pkt))) { | |
- self->pkt_xrun = 1; | |
- return 0; | |
- } | |
- | |
- /* Retrieve empty (but allocated) packet */ | |
- av_fifo_generic_read(self->new_pkts, &pkt, sizeof(pkt), NULL); | |
- | |
- pkt_data = (float *) pkt.data; | |
- latency = 0; | |
- | |
- /* Copy and interleave audio data from the JACK buffer into the packet */ | |
- for (i = 0; i < self->nports; i++) { | |
- #if HAVE_JACK_PORT_GET_LATENCY_RANGE | |
- jack_latency_range_t range; | |
- jack_port_get_latency_range(self->ports[i], JackCaptureLatency, &range); | |
- latency += range.max; | |
- #else | |
- latency += jack_port_get_total_latency(self->client, self->ports[i]); | |
- #endif | |
- buffer = jack_port_get_buffer(self->ports[i], self->buffer_size); | |
- for (j = 0; j < self->buffer_size; j++) | |
- pkt_data[j * self->nports + i] = buffer[j]; | |
- } | |
- | |
- /* Timestamp the packet with the cycle start time minus the average latency */ | |
- pkt.pts = (cycle_time - (double) latency / (self->nports * self->sample_rate)) * 1000000.0; | |
- | |
- /* Send the now filled packet back, and increase packet counter */ | |
- av_fifo_generic_write(self->filled_pkts, &pkt, sizeof(pkt), NULL); | |
- sem_post(&self->packet_count); | |
- | |
- return 0; | |
-} | |
- | |
-static void shutdown_callback(void *arg) | |
-{ | |
- JackData *self = arg; | |
- self->client = NULL; | |
-} | |
- | |
-static int xrun_callback(void *arg) | |
-{ | |
- JackData *self = arg; | |
- self->jack_xrun = 1; | |
- ff_timefilter_reset(self->timefilter); | |
- return 0; | |
-} | |
- | |
-static int supply_new_packets(JackData *self, AVFormatContext *context) | |
-{ | |
- AVPacket pkt; | |
- int test, pkt_size = self->buffer_size * self->nports * sizeof(float); | |
- | |
- /* Supply the process callback with new empty packets, by filling the new | |
- * packets FIFO buffer with as many packets as possible. process_callback() | |
- * can't do this by itself, because it can't allocate memory in realtime. */ | |
- while (av_fifo_space(self->new_pkts) >= sizeof(pkt)) { | |
- if ((test = av_new_packet(&pkt, pkt_size)) < 0) { | |
- av_log(context, AV_LOG_ERROR, "Could not create packet of size %d\n", pkt_size); | |
- return test; | |
- } | |
- av_fifo_generic_write(self->new_pkts, &pkt, sizeof(pkt), NULL); | |
- } | |
- return 0; | |
-} | |
+#include "jack.h" | |
static int start_jack(AVFormatContext *context) | |
{ | |
@@ -172,9 +48,10 @@ static int start_jack(AVFormatContext *context) | |
} | |
sem_init(&self->packet_count, 0, 0); | |
- | |
- self->sample_rate = jack_get_sample_rate(self->client); | |
- self->ports = av_malloc_array(self->nports, sizeof(*self->ports)); | |
+ if(!self->sample_rate) | |
+ self->sample_rate = jack_get_sample_rate(self->client); | |
+ if(!self->ports) | |
+ self->ports = av_malloc_array(self->nports, sizeof(*self->ports)); | |
if (!self->ports) | |
return AVERROR(ENOMEM); | |
self->buffer_size = jack_get_buffer_size(self->client); | |
@@ -185,7 +62,7 @@ static int start_jack(AVFormatContext *context) | |
snprintf(str, sizeof(str), "input_%d", i + 1); | |
self->ports[i] = jack_port_register(self->client, str, | |
JACK_DEFAULT_AUDIO_TYPE, | |
- JackPortIsInput, 0); | |
+ self->port_type, 0); | |
if (!self->ports[i]) { | |
av_log(context, AV_LOG_ERROR, "Unable to register port %s:%s\n", | |
context->filename, str); | |
@@ -214,23 +91,23 @@ static int start_jack(AVFormatContext *context) | |
jack_client_close(self->client); | |
return AVERROR(ENOMEM); | |
} | |
- if ((test = supply_new_packets(self, context))) { | |
- jack_client_close(self->client); | |
- return test; | |
- } | |
return 0; | |
} | |
-static void free_pkt_fifo(AVFifoBuffer **fifo) | |
+static void shutdown_callback(void *arg) | |
{ | |
- AVPacket pkt; | |
- while (av_fifo_size(*fifo)) { | |
- av_fifo_generic_read(*fifo, &pkt, sizeof(pkt), NULL); | |
- av_packet_unref(&pkt); | |
- } | |
- av_fifo_freep(fifo); | |
+ JackData *self = arg; | |
+ self->client = NULL; | |
+} | |
+ | |
+static int xrun_callback(void *arg) | |
+{ | |
+ JackData *self = arg; | |
+ self->jack_xrun = 1; | |
+ ff_timefilter_reset(self->timefilter); | |
+ return 0; | |
} | |
static void stop_jack(JackData *self) | |
@@ -247,122 +124,12 @@ static void stop_jack(JackData *self) | |
ff_timefilter_destroy(self->timefilter); | |
} | |
-static int audio_read_header(AVFormatContext *context) | |
-{ | |
- JackData *self = context->priv_data; | |
- AVStream *stream; | |
- int test; | |
- | |
- if ((test = start_jack(context))) | |
- return test; | |
- | |
- stream = avformat_new_stream(context, NULL); | |
- if (!stream) { | |
- stop_jack(self); | |
- return AVERROR(ENOMEM); | |
- } | |
- | |
- stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
-#if HAVE_BIGENDIAN | |
- stream->codec->codec_id = AV_CODEC_ID_PCM_F32BE; | |
-#else | |
- stream->codec->codec_id = AV_CODEC_ID_PCM_F32LE; | |
-#endif | |
- stream->codec->sample_rate = self->sample_rate; | |
- stream->codec->channels = self->nports; | |
- | |
- avpriv_set_pts_info(stream, 64, 1, 1000000); /* 64 bits pts in us */ | |
- return 0; | |
-} | |
- | |
-static int audio_read_packet(AVFormatContext *context, AVPacket *pkt) | |
+static void free_pkt_fifo(AVFifoBuffer **fifo) | |
{ | |
- JackData *self = context->priv_data; | |
- struct timespec timeout = {0, 0}; | |
- int test; | |
- | |
- /* Activate the JACK client on first packet read. Activating the JACK client | |
- * means that process_callback() starts to get called at regular interval. | |
- * If we activate it in audio_read_header(), we're actually reading audio data | |
- * from the device before instructed to, and that may result in an overrun. */ | |
- if (!self->activated) { | |
- if (!jack_activate(self->client)) { | |
- self->activated = 1; | |
- av_log(context, AV_LOG_INFO, | |
- "JACK client registered and activated (rate=%dHz, buffer_size=%d frames)\n", | |
- self->sample_rate, self->buffer_size); | |
- } else { | |
- av_log(context, AV_LOG_ERROR, "Unable to activate JACK client\n"); | |
- return AVERROR(EIO); | |
- } | |
- } | |
- | |
- /* Wait for a packet coming back from process_callback(), if one isn't available yet */ | |
- timeout.tv_sec = av_gettime() / 1000000 + 2; | |
- if (sem_timedwait(&self->packet_count, &timeout)) { | |
- if (errno == ETIMEDOUT) { | |
- av_log(context, AV_LOG_ERROR, | |
- "Input error: timed out when waiting for JACK process callback output\n"); | |
- } else { | |
- char errbuf[128]; | |
- int ret = AVERROR(errno); | |
- av_strerror(ret, errbuf, sizeof(errbuf)); | |
- av_log(context, AV_LOG_ERROR, "Error while waiting for audio packet: %s\n", | |
- errbuf); | |
- } | |
- if (!self->client) | |
- av_log(context, AV_LOG_ERROR, "Input error: JACK server is gone\n"); | |
- | |
- return AVERROR(EIO); | |
- } | |
- | |
- if (self->pkt_xrun) { | |
- av_log(context, AV_LOG_WARNING, "Audio packet xrun\n"); | |
- self->pkt_xrun = 0; | |
- } | |
- | |
- if (self->jack_xrun) { | |
- av_log(context, AV_LOG_WARNING, "JACK xrun\n"); | |
- self->jack_xrun = 0; | |
+ AVPacket pkt; | |
+ while (av_fifo_size(*fifo)) { | |
+ av_fifo_generic_read(*fifo, &pkt, sizeof(pkt), NULL); | |
+ av_packet_unref(&pkt); | |
} | |
- | |
- /* Retrieve the packet filled with audio data by process_callback() */ | |
- av_fifo_generic_read(self->filled_pkts, pkt, sizeof(*pkt), NULL); | |
- | |
- if ((test = supply_new_packets(self, context))) | |
- return test; | |
- | |
- return 0; | |
-} | |
- | |
-static int audio_read_close(AVFormatContext *context) | |
-{ | |
- JackData *self = context->priv_data; | |
- stop_jack(self); | |
- return 0; | |
-} | |
- | |
-#define OFFSET(x) offsetof(JackData, x) | |
-static const AVOption options[] = { | |
- { "channels", "Number of audio channels.", OFFSET(nports), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, | |
- { NULL }, | |
-}; | |
- | |
-static const AVClass jack_indev_class = { | |
- .class_name = "JACK indev", | |
- .item_name = av_default_item_name, | |
- .option = options, | |
- .version = LIBAVUTIL_VERSION_INT, | |
- .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, | |
-}; | |
- | |
-AVInputFormat ff_jack_demuxer = { | |
- .name = "jack", | |
- .long_name = NULL_IF_CONFIG_SMALL("JACK Audio Connection Kit"), | |
- .priv_data_size = sizeof(JackData), | |
- .read_header = audio_read_header, | |
- .read_packet = audio_read_packet, | |
- .read_close = audio_read_close, | |
- .flags = AVFMT_NOFILE, | |
- .priv_class = &jack_indev_class, | |
-}; | |
+ av_fifo_freep(fifo); | |
+} | |
\ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment