[FFmpeg-devel] [PATCH] libavdevice: JACK demuxer

Måns Rullgård mans
Sat Feb 28 02:08:42 CET 2009


Olivier Guilyardi <list at samalyse.com> writes:

> Index: libavdevice/jack_audio.c
> ===================================================================
> --- libavdevice/jack_audio.c	(revision 0)
> +++ libavdevice/jack_audio.c	(revision 0)
> @@ -0,0 +1,303 @@
> +/*
> + * JACK Audio Connection Kit interface
> + * Copyright (c) 2009 Samalyse
> + * Author: Olivier Guilyardi <olivier samalyse com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "config.h"
> +#include <semaphore.h>
> +#include <jack/jack.h>
> +#include <jack/ringbuffer.h>
> +
> +#include "libavutil/log.h"
> +#include "libavcodec/avcodec.h"
> +#include "libavformat/avformat.h"
> +
> +/*
> + * Size of the internal ringbuffer as a number of jack buffers
> + */
> +#define RING_NBUFFERS 4
> +
> +typedef enum OverrunType {
> +    CTL_OVERRUN   = 1,
> +    DATA_OVERRUN  = 2,
> +    XRUN          = 4
> +} OverrunType;
> +
> +typedef struct {
> +    jack_client_t *     client;
> +    int                 activated;
> +    sem_t               mutex;

That is a confusing name.  A semaphore is not a mutex.

> +    jack_nframes_t      sample_rate;
> +    jack_nframes_t      buffer_size;
> +    jack_port_t **      ports;
> +    int                 nports;
> +    jack_ringbuffer_t * ctl_rb;
> +    jack_ringbuffer_t * data_rb;
> +    float *             channel_buffer;
> +    OverrunType         overrun;
> +} PrivateData;
> +
> +typedef struct {
> +    int64_t         pts;
> +    jack_nframes_t  size;
> +    OverrunType     overrun;
> +} PacketControlInfo;
> +
> +static int process_callback(jack_nframes_t nframes, void *arg)
> +{
> +    int i;
> +    PrivateData *self = arg;
> +    void * buffer;
> +    PacketControlInfo info;
> +    jack_nframes_t latency, cycle_delay;
> +
> +    if (!self->client)
> +        return 0;
> +
> +    if (jack_ringbuffer_write_space(self->ctl_rb) >= sizeof(info)) {
> +        info.size = jack_ringbuffer_write_space(self->data_rb) / sizeof(float) / self->nports;
> +
> +        if (info.size > nframes) {
> +            info.size = nframes;
> +        } else if (info.size < nframes) {
> +            self->overrun |= DATA_OVERRUN;
> +        }
> +
> +        if (info.size > 0) {
> +            latency = 0;
> +            for (i = 0; i < self->nports; i++) {
> +                latency += jack_port_get_total_latency(self->client, self->ports[i]);
> +                buffer = jack_port_get_buffer(self->ports[i], info.size);
> +                jack_ringbuffer_write(self->data_rb, (char *) buffer, info.size * sizeof(float));
> +            }
> +
> +            cycle_delay = jack_frames_since_cycle_start(self->client);
> +            info.pts = av_gettime() - ((float) latency / self->nports + cycle_delay) * 1000000.0 / self->sample_rate;
> +
> +            info.overrun = self->overrun;
> +            jack_ringbuffer_write(self->ctl_rb, (char *) &info, sizeof(info));
> +            sem_post(&self->mutex);

This will post the semaphore once each time this function is called
without overrun.

> +            self->overrun = 0;
> +        }
> +    } else {
> +        self->overrun |= CTL_OVERRUN;
> +    }
> +    return 0;
> +}
> +

[...]

> +static int audio_read_packet(AVFormatContext *context, AVPacket *pkt)
> +{
> +    PrivateData *self = context->priv_data;
> +    PacketControlInfo info;
> +    int pkt_size, i, j;
> +    float *output_data;
> +    struct timespec timeout = {0, 0};
> +
> +    if (!self->activated && activate_jack(self, context))
> +        return AVERROR(EIO);
> +
> +    timeout.tv_sec = av_gettime() / 1000000 + 2;
> +    if (sem_timedwait(&self->mutex, &timeout)) {

This will wait on the semaphore once each time this function is
called.  If these calls are less frequent than the calls to
process_callback(), the semaphore count will accumulate until it is
positive even though the buffer has no data, and an underrun will be
reported.

I think you should be using a mutex and condition variable instead.

-- 
M?ns Rullg?rd
mans at mansr.com




More information about the ffmpeg-devel mailing list