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

Olivier Guilyardi list
Wed Mar 4 14:33:47 CET 2009


Attached: jack demuxer patch 0.8

This patch fixes the jack demuxer compatibility with the timefilter libavformat
patch version 0.3.

It's also better commented than previous versions.

I'm running out of time, and will now only fix bugs, if any. Feel free to use my
patches, or let them sleep otherwise.

Michael Niedermayer wrote:

[...]
>> +/*
>> + * Size of the internal ringbuffer as a number of jack buffers
>> + * Must be greater than or equal to 2
>> + */
>> +#define RING_NBUFFERS 4
> 
> that isnt doxygen compatible

Fixed

> [...]
>> +#ifdef WORDS_BIGENDIAN
>> +    stream->codec->codec_id = CODEC_ID_PCM_F32BE;
>> +#else
>> +    stream->codec->codec_id = CODEC_ID_PCM_F32LE;
>> +#endif
> 
> I suspect we should add a CODEC_ID_PCM_F32NE that is #defined to
> one of above to get rid of such #ifdefs in several places ...
> 
> 
>> +    stream->codec->sample_rate = self->sample_rate;
>> +    stream->codec->channels = self->nports;
>> +
>> +    av_set_pts_info(stream, 64, 1, 1000000);  /* 64 bits pts in us */
>> +    return 0;
>> +}
>> +
>> +static int audio_read_packet(AVFormatContext *context, AVPacket *pkt)
>> +{
>> +    PrivateData *self = context->priv_data;
>> +    int pkt_size;
>> +    struct timespec timeout = {0, 0};
>> +
> 
>> +    if (!self->activated && activate_jack(self, context))
>> +        return AVERROR(EIO);
> 
> this looks like it belongs in audio_read_header()

I added a comment about this. I actually moved it from audio_read_header() into
audio_read_packet() in an attempt to fix the (single) overrun that always occur
when launching ffmpeg. That didn't fix it, but I believe that may be useful with
other programs.

>> +
>> +    timeout.tv_sec = av_gettime() / 1000000 + 2;
>> +    if (sem_timedwait(&self->packet_signal, &timeout)) {
>> +        if (errno == ETIMEDOUT) {
>> +            av_log(context, AV_LOG_ERROR,
>> +                   "Input error: timed out when waiting for JACK process callback output\n");
>> +        } else {
>> +            av_log(context, AV_LOG_ERROR, "Error while waiting for audio packet: %s\n",
>> +                   strerror(errno));
>> +        }
>> +        if (!self->client) {
>> +            av_log(context, AV_LOG_ERROR, "Input error: JACK server is gone\n");
>> +        }
>> +        return AVERROR(EIO);
>> +    }
>> +
>> +    if (self->overrun) {
>> +        av_log(context, AV_LOG_WARNING, "Packet ringbuffer overrun\n");
>> +        self->overrun = 0;
>> +    }
>> +
>> +    if (self->xrun) {
>> +        av_log(context, AV_LOG_WARNING, "JACK xrun\n");
>> +        self->xrun = 0;
>> +    }
>> +
> 
>> +    self->reader_index = (self->reader_index + 1) % RING_NBUFFERS;
>> +
> 
>> +    memcpy(pkt, self->ringbuffer + self->reader_index, sizeof(*pkt));
> 
> *pkt= self->ringbuffer[self->reader_index];
> 
> also it seems 1 entry in the ring buffer cant be used with your
> implementation
> 
> maybe the following is better:
> process_callback(){
>     if((uint8_t)(writer_index - reader_index) < RING_SIZE){
>         write at buffer[writer_index & (RING_SIZE-1)];
>         writer_index++;
>     }
> }
> 
> read_packet(){
>     if(writer_index == reader_index)
>         return AVERROR(EAGAIN);
> 
>     take packet from buffer[reader_index & (RING_SIZE-1)];
>     buffer[reader_index & (RING_SIZE-1)]= av_new_packet();
>     reader_index++;
> }
> 
> note, both writer_index and reader_index must be unsigned for above
> to work, and probably its best if they are uint8_t to exclude any issues
> with the writes to them not being done in one piece.

Okay, I've completely changed this. My experience with lock free ringbuffers
shows that it's hard to tell what is safe and what is not from a theoretical
point of view (and there are many such point of views...).

As of JACK 0.116, the jack ringbuffer has been thoroughly unit tested and fixed
(see the dozens of posts on LAD, LAU and jack-devel), on single/multi cpu, and
especially on weakly memory ordered ones (such as PowerPC SMP).

So I found a way to avoid superfluous copy operations, using 2 jack ringbuffers.
The idea is simple: audio_read_packet() sends newly allocated empty packets
through one ringbuffer. Then process_callback() retrieve one, directly copy and
interleave data into it, and send it back through another ringbuffer.

It's not possible to use one ringbuffer for this, because you can't both read
from and write into a jack ringbuffer from the same thread, that's the rule.

--
  Olivier

-------------- next part --------------
A non-text attachment was scrubbed...
Name: ffmpeg-r17804-jack-0.8.patch
Type: text/x-patch
Size: 13195 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090304/7ea18d56/attachment.bin>



More information about the ffmpeg-devel mailing list