aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2015-03-13 09:50:04 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2015-03-13 09:50:04 +0100
commitce10052a134f8b6c84112f5785a8b48cdc9bba22 (patch)
tree9509d2b169942a7c85eac93531fd2aa430ccecae
parent845746006e79d554478090126dbdab799299f9b3 (diff)
downloadtoolame-dab-ce10052a134f8b6c84112f5785a8b48cdc9bba22.tar.gz
toolame-dab-ce10052a134f8b6c84112f5785a8b48cdc9bba22.tar.bz2
toolame-dab-ce10052a134f8b6c84112f5785a8b48cdc9bba22.zip
Add libvlc input
-rw-r--r--Makefile8
-rw-r--r--audio_read.c16
-rw-r--r--options.h7
-rw-r--r--toolame.c34
-rw-r--r--vlc_input.c201
-rw-r--r--vlc_input.h43
6 files changed, 293 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index a2bc050..0698258 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,8 @@ HEADERS = \
toolame.h \
utils.h \
xpad.h \
- zmqoutput.h
+ zmqoutput.h \
+ vlc_input.h
c_sources = \
common.c \
@@ -60,7 +61,8 @@ c_sources = \
encode_new.c \
zmqoutput.c \
utils.c \
- xpad.c
+ xpad.c \
+ vlc_input.c
OBJ = $(c_sources:.c=.o)
@@ -98,7 +100,7 @@ CC_SWITCHES = $(OPTIM) $(REQUIRED) $(ARCH) $(PG) $(TWEAKS) $(WARNINGS) $(NEW_02L
PGM = toolame
-LIBS = -lm -lzmq -ljack -lpthread
+LIBS = -lm -lzmq -ljack -lpthread -lvlc
#nick burch's OS/2 fix gagravarr@SoftHome.net
UNAME = $(shell uname)
diff --git a/audio_read.c b/audio_read.c
index 007f020..20ac1dc 100644
--- a/audio_read.c
+++ b/audio_read.c
@@ -9,6 +9,7 @@
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include "audio_read.h"
+#include "vlc_input.h"
jack_port_t *input_port_left;
jack_port_t *input_port_right;
@@ -200,7 +201,7 @@ unsigned long read_samples (music_in_t* musicin, short sample_buffer[2304],
else
samples_read = samples_to_read;
- if (glopts.enable_jack) {
+ if (glopts.input_select == INPUT_SELECT_JACK) {
int f = 2;
while (jack_ringbuffer_read_space(rb) < f * samples_read) {
/* wait until process() signals more data */
@@ -229,12 +230,21 @@ unsigned long read_samples (music_in_t* musicin, short sample_buffer[2304],
free(jack_sample_buffer);
}
- else {
+ else if (glopts.input_select == INPUT_SELECT_WAV) {
if ((samples_read =
fread (sample_buffer, sizeof (short), (int) samples_read,
musicin->wav_input)) == 0)
- fprintf (stderr, "Hit end of audio data\n");
+ fprintf (stderr, "Hit end of WAV audio data\n");
}
+ else if (glopts.input_select == INPUT_SELECT_VLC) {
+ size_t bytes_read = vlc_in_read(sample_buffer, sizeof(short) * (int)samples_read);
+ if (bytes_read == 0) {
+ fprintf (stderr, "Hit end of VLC audio data\n");
+ }
+
+ samples_read = bytes_read / sizeof(short);
+ }
+
/*
Samples are big-endian. If this is a little-endian machine
we must swap
diff --git a/options.h b/options.h
index a03db04..899a6f1 100644
--- a/options.h
+++ b/options.h
@@ -1,6 +1,10 @@
#ifndef OPTIONS_H
#define OPTIONS_H
+#define INPUT_SELECT_JACK 1
+#define INPUT_SELECT_WAV 2
+#define INPUT_SELECT_VLC 3
+
typedef struct
{
int usepsy; /* TRUE by default, use the psy model */
@@ -16,10 +20,11 @@ typedef struct
float athlevel; /* 0 extra argument to the ATH equation -
used for VBR in LAME */
int verbosity; /* 2 by default. 0 is no output at all */
- int enable_jack; /* 1=use JACK input, 2=use wav input */
+ int input_select; /* 1=use JACK input, 2=use wav input, 3=use VLC input */
int show_level; /* 1=show the sox-like audio level measurement */
}
options;
options glopts;
#endif
+
diff --git a/toolame.c b/toolame.c
index c64744a..238197a 100644
--- a/toolame.c
+++ b/toolame.c
@@ -25,6 +25,7 @@
#include "toolame.h"
#include "xpad.h"
#include "utils.h"
+#include "vlc_input.h"
#include <assert.h>
@@ -48,7 +49,7 @@ void global_init (void)
glopts.vbrlevel = 0;
glopts.athlevel = 0;
glopts.verbosity = 2;
- glopts.enable_jack = 0;
+ glopts.input_select = 0;
}
/************************************************************************
@@ -569,7 +570,7 @@ int main (int argc, char **argv)
(FLOAT) sentBits / (frameNum * 1152) *
s_freq[header.version][header.sampling_frequency]);
- if (!glopts.enable_jack) {
+ if (glopts.input_select == INPUT_SELECT_WAV) {
if ( fclose (musicin.wav_input) != 0) {
fprintf (stderr, "Could not close \"%s\".\n", original_file_name);
exit (2);
@@ -597,15 +598,19 @@ void print_config (frame_info * frame, int *psy, char *inPath,
return;
fprintf (stderr, "--------------------------------------------\n");
- if (glopts.enable_jack) {
+ if (glopts.input_select == INPUT_SELECT_JACK) {
fprintf (stderr, "Input JACK\n");
fprintf (stderr, " name %s\n", musicin.jack_name);
}
- else {
+ else if (glopts.input_select == INPUT_SELECT_WAV) {
fprintf (stderr, "Input File : '%s' %.1f kHz\n",
(strcmp (inPath, "-") ? inPath : "stdin"),
s_freq[header->version][header->sampling_frequency]);
}
+ else if (glopts.input_select == INPUT_SELECT_VLC) {
+ fprintf (stderr, "Input VLC\n");
+ fprintf (stderr, " URI %s\n", inPath);
+ }
fprintf (stderr, "Output File: '%s'\n",
(strcmp (outPath, "-") ? outPath : "stdout"));
@@ -764,7 +769,7 @@ void parse_args (int argc, char **argv, frame_info * frame, int *psy,
int brate;
frame_header *header = frame->header;
int err = 0, i = 0;
- long samplerate;
+ long samplerate = 0;
/* preset defaults */
inPath[0] = '\0';
@@ -884,7 +889,7 @@ void parse_args (int argc, char **argv, frame_info * frame, int *psy,
break;
case 'j':
- glopts.enable_jack = 1;
+ glopts.input_select = INPUT_SELECT_JACK;
break;
case 'b':
@@ -957,6 +962,9 @@ void parse_args (int argc, char **argv, frame_info * frame, int *psy,
header->mode = MPG_MD_STEREO; /* force stereo mode */
header->mode_ext = 0;
break;
+ case 'V':
+ glopts.input_select = INPUT_SELECT_VLC;
+ break;
case 'l':
argUsed = 1;
glopts.athlevel = atof(arg);
@@ -1016,7 +1024,7 @@ void parse_args (int argc, char **argv, frame_info * frame, int *psy,
if (err)
usage (); /* If err has occured, then call usage() */
- if (!glopts.enable_jack && inPath[0] == '\0')
+ if (glopts.input_select != INPUT_SELECT_JACK && inPath[0] == '\0')
usage (); /* If not in jack-mode and no file specified, then call usage() */
if (outPath[0] == '\0') {
@@ -1024,13 +1032,13 @@ void parse_args (int argc, char **argv, frame_info * frame, int *psy,
new_ext (inPath, DFLT_EXT, outPath);
}
- if (glopts.enable_jack) {
+ if (glopts.input_select == INPUT_SELECT_JACK) {
musicin.jack_name = inPath;
*num_samples = MAX_U_32_NUM;
setup_jack(header, musicin.jack_name);
}
- else {
+ else if (glopts.input_select == INPUT_SELECT_WAV) {
if (!strcmp (inPath, "-")) {
musicin.wav_input = stdin; /* read from stdin */
*num_samples = MAX_U_32_NUM;
@@ -1042,6 +1050,14 @@ void parse_args (int argc, char **argv, frame_info * frame, int *psy,
parse_input_file (musicin.wav_input, inPath, header, num_samples);
}
}
+ else if (glopts.input_select == INPUT_SELECT_VLC) {
+ if (samplerate == 0) {
+ fprintf (stderr, "Samplerate not specified\n");
+ exit (1);
+ }
+ *num_samples = MAX_U_32_NUM;
+ vlc_in_prepare(glopts.verbosity, samplerate, inPath);
+ }
/* check for a valid bitrate */
if (brate == 0)
diff --git a/vlc_input.c b/vlc_input.c
new file mode 100644
index 0000000..fab8273
--- /dev/null
+++ b/vlc_input.c
@@ -0,0 +1,201 @@
+#include <stdlib.h>
+#include <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include "vlc_input.h"
+
+
+libvlc_instance_t *m_vlc;
+libvlc_media_player_t *m_mp;
+
+unsigned int vlc_rate;
+
+struct vlc_buffer *head_buffer;
+
+pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct vlc_buffer* vlc_buffer_new()
+{
+ struct vlc_buffer* node;
+ node = malloc(sizeof(struct vlc_buffer));
+ memset(node, 0, sizeof(struct vlc_buffer));
+ return node;
+}
+
+void vlc_buffer_free(struct vlc_buffer* node)
+{
+ if (node->buf) {
+ free(node->buf);
+ }
+
+ free(node);
+}
+
+size_t vlc_buffer_totalsize(struct vlc_buffer* node)
+{
+ size_t totalsize = 0;
+ for (; node != NULL; node = node->next) {
+ totalsize += node->size;
+ }
+
+ return totalsize;
+}
+
+// VLC Audio prerender callback, we must allocate a buffer here
+void prepareRender(
+ void* p_audio_data,
+ uint8_t** pp_pcm_buffer,
+ size_t size)
+{
+ *pp_pcm_buffer = malloc(size);
+ return;
+}
+
+
+
+// Audio postrender callback
+void handleStream(
+ void* p_audio_data,
+ uint8_t* p_pcm_buffer,
+ unsigned int channels,
+ unsigned int rate,
+ unsigned int nb_samples,
+ unsigned int bits_per_sample,
+ size_t size,
+ int64_t pts)
+{
+ assert(channels == 2);
+ assert(rate == vlc_rate);
+ assert(bits_per_sample == 16);
+
+ const size_t max_length = 4 * size;
+
+ for (;;) {
+ pthread_mutex_lock(&buffer_lock);
+
+ if (vlc_buffer_totalsize(head_buffer) < max_length) {
+ struct vlc_buffer* newbuf = vlc_buffer_new();
+
+ newbuf->buf = p_pcm_buffer;
+ newbuf->size = size;
+
+ // Append the new buffer to the end of the linked list
+ struct vlc_buffer* tail = head_buffer;
+ while (tail->next) {
+ tail = tail->next;
+ }
+ tail->next = newbuf;
+
+ pthread_mutex_unlock(&buffer_lock);
+ return;
+ }
+
+ pthread_mutex_unlock(&buffer_lock);
+ usleep(100);
+ }
+}
+
+int vlc_in_prepare(unsigned verbosity, unsigned int rate, const char* uri)
+{
+ int err;
+ fprintf(stderr, "Initialising VLC...\n");
+
+ vlc_rate = rate;
+
+ // VLC options
+ char smem_options[512];
+ snprintf(smem_options, sizeof(smem_options),
+ "#transcode{acodec=s16l,samplerate=%d}:"
+ // We are using transcode because smem only support raw audio and
+ // video formats
+ "smem{"
+ "audio-postrender-callback=%lld,"
+ "audio-prerender-callback=%lld"
+ "}",
+ vlc_rate,
+ (long long int)(intptr_t)(void*)&handleStream,
+ (long long int)(intptr_t)(void*)&prepareRender);
+
+ char verb_options[512];
+ snprintf(verb_options, sizeof(verb_options),
+ "--verbose=%d", verbosity);
+
+ const char * const vlc_args[] = {
+ verb_options,
+ "--sout", smem_options // Stream to memory
+ };
+
+ // Launch VLC
+ m_vlc = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
+
+ // Load the media
+ libvlc_media_t *m;
+ m = libvlc_media_new_location(m_vlc, uri);
+ m_mp = libvlc_media_player_new_from_media(m);
+ libvlc_media_release(m);
+
+ // Allocate the list
+ head_buffer = vlc_buffer_new();
+
+ // Start playing
+ libvlc_media_player_play(m_mp);
+
+ fprintf(stderr, "VLC launched.\n");
+ return 0;
+}
+
+size_t vlc_in_read(void *buf, size_t len)
+{
+ size_t requested = len;
+ for (;;) {
+ pthread_mutex_lock(&buffer_lock);
+
+ if (vlc_buffer_totalsize(head_buffer) >= len) {
+ while (len >= head_buffer->size) {
+ if (head_buffer->buf) {
+ // Get all the data from this list element
+ memcpy(buf, head_buffer->buf, head_buffer->size);
+
+ buf += head_buffer->size;
+ len -= head_buffer->size;
+ }
+
+ if (head_buffer->next) {
+ struct vlc_buffer *next_head = head_buffer->next;
+ vlc_buffer_free(head_buffer);
+ head_buffer = next_head;
+ }
+ else {
+ vlc_buffer_free(head_buffer);
+ head_buffer = vlc_buffer_new();
+ break;
+ }
+ }
+
+ if (len > 0) {
+ assert(len < head_buffer->size);
+
+ memcpy(buf, head_buffer->buf, len);
+
+ // split the current head into two parts
+ size_t remaining = head_buffer->size - len;
+ uint8_t *newbuf = malloc(remaining);
+
+ memcpy(newbuf, head_buffer->buf + len, remaining);
+ free(head_buffer->buf);
+ head_buffer->buf = newbuf;
+ head_buffer->size = remaining;
+ }
+
+ pthread_mutex_unlock(&buffer_lock);
+ return requested;
+ }
+
+ pthread_mutex_unlock(&buffer_lock);
+ usleep(100);
+ }
+
+ abort();
+}
+
diff --git a/vlc_input.h b/vlc_input.h
new file mode 100644
index 0000000..976a7e7
--- /dev/null
+++ b/vlc_input.h
@@ -0,0 +1,43 @@
+#ifndef __VLC_INPUT_H_
+#define __VLC_INPUT_H_
+
+#include <stdint.h>
+#include <vlc/vlc.h>
+
+
+// A linked list structure for the incoming buffers
+struct vlc_buffer {
+ uint8_t *buf;
+ size_t size;
+ struct vlc_buffer *next;
+};
+
+struct vlc_buffer* vlc_buffer_new();
+void vlc_buffer_free(struct vlc_buffer* node);
+
+
+// VLC Audio prerender callback
+void prepareRender(
+ void* p_audio_data,
+ uint8_t** pp_pcm_buffer,
+ size_t size);
+
+// Audio postrender callback
+void handleStream(
+ void* p_audio_data,
+ uint8_t* p_pcm_buffer,
+ unsigned int channels,
+ unsigned int rate,
+ unsigned int nb_samples,
+ unsigned int bits_per_sample,
+ size_t size,
+ int64_t pts);
+
+// Open the VLC input
+int vlc_in_prepare(unsigned verbosity, unsigned int rate, const char* uri);
+
+// Read len audio bytes into buf
+size_t vlc_in_read(void *buf, size_t len);
+
+#endif
+