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

Michael Niedermayer michaelni
Thu Mar 19 15:00:03 CET 2009


On Thu, Mar 19, 2009 at 01:30:48AM +0100, Olivier Guilyardi wrote:
> Attached: jack demuxer patch 0.12
> 
> Diego Biurrun wrote:
> > On Tue, Mar 17, 2009 at 02:11:07PM +0100, Olivier Guilyardi wrote:
> >> Diego Biurrun wrote:
> >>> On Tue, Mar 17, 2009 at 12:40:13PM +0100, Olivier Guilyardi wrote:
> >>>> Diego Biurrun wrote:
[...]
> +/**
> + * Size of the internal FIFO buffers as a number of audio packets
> + */
> +#define FIFO_PACKETS_NUM 16
> +
> +typedef struct {
> +    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;

> +    unsigned int        new_pkts_size;
> +    AVFifoBuffer *      filled_pkts;

> +    unsigned int        filled_pkts_size;

maybe ive been too tired (yes i suggested it) but these make no sense
FIFO_PACKETS_NUM should be used


> +    int                 overrun;
> +    int                 underrun;
> +    int                 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,
> +                                      (double) av_gettime() / 1000000.0 - cycle_delay / self->sample_rate,
> +                                      self->buffer_size);
> +
> +    /* Check if an empty packet is available, so that we can fill it with audio data */
> +    if (av_fifo_size(self->new_pkts) < sizeof(pkt)) {
> +        self->underrun = 1;
> +        return 0;
> +    }
> +
> +    /* Check if there's enough space to send the filled packet */
> +    if (self->filled_pkts_size - av_fifo_size(self->filled_pkts) < sizeof(pkt)) {
> +        self->overrun = 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++) {
> +        latency += jack_port_get_total_latency(self->client, self->ports[i]);
> +        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 - (latency / self->nports) / self->sample_rate) * 1000000.0;

isnt
(latency / self->nports) / self->sample_rate
an integer in seconds aka pretty inaccurate?
also (nitpick), id write
latency / (self->nports * self->sample_rate)
avoiding a slow division

[...]
> +static int supply_new_packets(JackData *self, AVFormatContext *context)
> +{
> +    AVPacket pkt;
> +    int 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 (self->new_pkts_size - av_fifo_size(self->new_pkts) >= sizeof(pkt)) {
> +        if (av_new_packet(&pkt, pkt_size) < 0) {
> +            av_log(context, AV_LOG_ERROR, "Could not create packet of size %d\n", pkt_size);
> +            return AVERROR(EIO);

the error should be either the one returned by av_new_packet() or ENOMEM
which is what the error would be


> +        }
> +        av_fifo_generic_write(self->new_pkts, &pkt, sizeof(pkt), NULL);
> +    }
> +    return 0;
> +}
> +
> +static int start_jack(AVFormatContext *context, AVFormatParameters *params)
> +{
> +    JackData *self = context->priv_data;
> +    jack_status_t status;
> +    int i, test;
> +    double o, period;
> +
> +    /* Register as a JACK client, using the context filename as client name. */
> +    self->client = jack_client_open(context->filename, 0, &status);
> +    if (!self->client) {
> +        av_log(context, AV_LOG_ERROR, "Unable to register as a JACK client\n");
> +        return AVERROR(EIO);
> +    }
> +
> +    sem_init(&self->packet_count, 0, 0);
> +

> +    self->overrun     = 0;
> +    self->xrun        = 0;
> +    self->activated   = 0;

redundant

[...]
> +    self->timefilter  = ff_timefilter_new (1 / self->sample_rate, sqrt(2 * o), o * o);

is the division not missing a float or doubl cast?


[...]
> +static int activate_jack(JackData *self, AVFormatContext *context)
> +{
> +    if (!jack_activate(self->client)) {
> +        self->activated = 1;
> +    } else {
> +        av_log(context, AV_LOG_ERROR, "Unable to activate JACK client\n");
> +        return -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);
> +
> +    return 0;

that stuff would fit nicer in the if() so both sides end in return

anyway, id this function really needed?
simply calling jack_activate() and setting activated seems simpler


[...]
> +    if (self->overrun) {
> +        av_log(context, AV_LOG_WARNING, "Audio packet overrun\n");
> +        self->overrun = 0;
> +    }
> +
> +    if (self->underrun) {
> +        av_log(context, AV_LOG_WARNING, "Audio packet underrun\n");
> +        self->underrun = 0;
> +    }
> +
> +    if (self->xrun) {
> +        av_log(context, AV_LOG_WARNING, "JACK xrun\n");
> +        self->xrun = 0;
> +    }

can xrun be != overrun || underrun ?
if not it is redundant

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I have often repented speaking, but never of holding my tongue.
-- Xenocrates
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090319/c8168a9e/attachment.pgp>



More information about the ffmpeg-devel mailing list