diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2015-03-13 09:50:04 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2015-03-13 09:50:04 +0100 |
commit | ce10052a134f8b6c84112f5785a8b48cdc9bba22 (patch) | |
tree | 9509d2b169942a7c85eac93531fd2aa430ccecae | |
parent | 845746006e79d554478090126dbdab799299f9b3 (diff) | |
download | toolame-dab-ce10052a134f8b6c84112f5785a8b48cdc9bba22.tar.gz toolame-dab-ce10052a134f8b6c84112f5785a8b48cdc9bba22.tar.bz2 toolame-dab-ce10052a134f8b6c84112f5785a8b48cdc9bba22.zip |
Add libvlc input
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | audio_read.c | 16 | ||||
-rw-r--r-- | options.h | 7 | ||||
-rw-r--r-- | toolame.c | 34 | ||||
-rw-r--r-- | vlc_input.c | 201 | ||||
-rw-r--r-- | vlc_input.h | 43 |
6 files changed, 293 insertions, 16 deletions
@@ -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 @@ -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 + @@ -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 + |