[FFmpeg-devel] v4l2: bug #1570 and possible solution
Giorgio Vazzana
mywing81 at gmail.com
Wed Feb 13 15:19:00 CET 2013
2013/2/13 Michael Niedermayer <michaelni at gmx.at>:
> On Tue, Feb 12, 2013 at 07:53:29PM +0100, Giorgio Vazzana wrote:
>> 2013/2/12 Michael Niedermayer <michaelni at gmx.at>:
>> > On Tue, Feb 12, 2013 at 06:01:10PM +0100, Giorgio Vazzana wrote:
>> >> 2013/2/12 Michael Niedermayer <michaelni at gmx.at>:
>> >> > On Tue, Feb 12, 2013 at 12:40:21PM +0100, Giorgio Vazzana wrote:
>> >> >> 2013/2/12 Michael Niedermayer <michaelni at gmx.at>:
>> >> >> +static void mmap_release_buffer(AVPacket *pkt)
>> >> >> +{
>> >> >> + struct buff_data *buf_descriptor = pkt->priv;
>> >> >> +
>> >> >> + if (pkt->data == NULL)
>> >> >> + return;
>> >> >> +
>> >> >> + if (buf_descriptor->buffer_copied) {
>> >> >> + av_free(pkt->data);
>> >> >> + } else {
>> >> >> + if (!enqueue_buffer(buf_descriptor->fd, buf_descriptor->index))
>> >> >
>> >> >> + (*buf_descriptor->buffers_dequeued)--;
>> >> >
>> >> > the deallocation of packets could happen from different thread(s)
>> >> > so i think this needs either a mutex, an atomic decrement or some
>> >> > lockless algorithm to achive the same
>> >>
>> >> Ok, I've tried to implement the solution using the mutex. Please comment.
>> >>
>> >> We can use this approach, or the easiest (and slightly slower?)
>> >> solution would be copying every frame/buffer to the memory allocated
>> >> for the corresponding packet.
>> >
>> > if you want to avoid the dependancy on pthreads, one way that should
>> > work is to use an array which size matches the maximum number of
>> > buffers, inited to 0 each time a buffer is allocated its entry is set
>> > to 1, when its freed its set to 0. to find out how many buffers are
>> > left the whole array would need to be scanned and remaining 0 elements
>> > counted.
>>
>> I will have to think about this in the following days, but for now I
>> do not see how this can work: suppose we consider the following
>> example:
>>
>> Initialization:
>> // let's suppose the number of buffers allocated by the v4l2
>> // driver is 10. This is also the lenght of the incoming and
>> // outgoing queues, which are organized as FIFO
>> buffers_obtained = 10;
>>
>> // allocate and clear array
>> int *array = calloc(buffers_obtained, sizeof(*array));
>>
>> // enqueue all the buffers to the incoming FIFO and start capturing
>> start_streaming();
>>
>>
>
>> Thread0 will do this:
>> // when we want to read a frame, we dequeue a buffer from the
>> // outgoing FIFO
>> dequeue_buffer(&buf);
>> // signal that a particular buffer has been dequeued
>> array[buf.index] = 1;
>>
>>
>> Thread1 will do this:
>> // count the numbers of buffers still in the incoming FIFO
>> int i, count = 0;
>> for (i = 0; i < buffers_obtained; i++)
>> if (array[i] == 0)
>> count++;
>
> This is not possible
> you imply that v4l2s read packet is itself called from 2 threads at
> the same time
> The only thing that can allocate packets/dequeue buffers is v4l2s
> read packet
> The only thing that has to count the available buffers is v4l2s read
> packet (that is for choosing where to allocate the next packet)
Ok, I was thinking at the more general case. Let's suppose only one
thread can call v4l2_read_packet().
It is possible I have not understood correctly the technique you
propose, so I'm sorry if I'm asking what might be a simple question.
Please look at this example:
Only one thread, Thread0, can do this:
// to read a frame, we dequeue a buffer from the outgoing FIFO
dequeue_buffer(&buf);
// signal that a particular buffer has been dequeued
array[buf.index] = 1;
// count the numbers of buffers still in the incoming FIFO
count = 0;
for (i = 0; i < buffers_obtained; i++)
if (array[i] == 0)
count++;
if (count == 0) {
copy_bufferdata_to_packet();
enqueue_buffer(buf.index);
array[buf.index] = 0;
} else {
copy_only_pointer_to_bufferdata_to_packet();
}
Another thread, or set of threads, will call the packet destructor:
if (bufferdata_was_copied_to_packet) {
free(pkt->data);
} else {
// pkt->data points to the buffer memory region, we need to
// enqueue this buffer
enqueue_buffer(pkt->priv->index);
// signal that the buffer has been enqueued
array[index] = 0;
}
I still see at least two threads writing on array, so to avoid a race
condition we still need a semaphore/mutex. If my reasoning is wrong,
could you propose an example that shows how this can be implemented
without a mutex, or point me to a place when I can read about it?
Thanks, your help is much appreciated.
Giorgio Vazzana
More information about the ffmpeg-devel
mailing list