Hi Mark,

On Tue, Aug 30, 2011 at 1:05 AM, Mark Kenna
<[email protected]> wrote:
> On 26/08/2011 23:40, Ronald S. Bultje wrote:
>> On Fri, Aug 26, 2011 at 6:15 AM, Mark Kenna
>> <[email protected]>  wrote:
>>> I have 4 AVFrames holding YUV420p data and I want to join them together
>>> into
>>> a single AVFrame for encoding, in effect tiling the output like so:
>>>
>>> [ ][ ]
>>> [ ][ ]
>>>
>>> Is LibAv able to do this without first converting to RGB and splicing
>>> them
>>> together?
>>
>> I don't think you ever need to convert to RGB.
>>
>> You can't splice them together. However, you can make it easier. That
>> is, implement your own get_buffer callback and allocate one big buffer
>> with double strides and set offsets correctly so it puts it exactly at
>> these positions. (I hope that makes sense, I can provide more detail
>> if that is confusing.)
>
> I think I know where you are coming from but can you explain in more detail
> just to be sure? Perhaps some sample code if there is any?

I don't have any sample code, but let me explain with a little more detail.

Step 1: implement a get_buffer callback in your application. This
means that when Libav tries to decode a frame, it doesn't put it in
its own buffer, but uses your application's buffer allocation
mechanism instead. (This is AVCodecContext->get_buffer.)

Step 2: (this requires that you know which buffers are to be placed in
which order, but I assume you know that already.) using your own
get_buffer callback, don't allocate one buffer per frame, but instead
one 2x2-sized buffer per 4 frames. This means, that when you fill the
AVFrame.data[]/linesize[] of the buffer, you don't av_malloc() buffers
for each, but rather a buffer that is twice the width and twice the
height of the picture to be decoded.

So instead of:

static int my_get_buffer(...)
{
    buffer->data[0] = av_malloc(height * buffer->linesize[0]);
    // etc. for data[1]/[2]
}

you do:

static int my_get_buffer(...)
{
    if (need_new_cache_buffer) {
        cache_buffer[0] = av_malloc(buffer->linesize[0] * 2 * height * 2);
        // etc. for cache_buffer[1]/[2]
    }

    // int position = 0 for topleft, 1 for top right, 2 for bottom
left, 3 for bottom right
    buffer->data[0] = cache_buffer[0] + ((position & 1) + position &
2) * height) * buffer->linesize[0];
    // etc. for data[1]/[2]
}

what will happen now is that the data is automatically filled into the
relevant regions of the output buffer, no need to memcpy() after
decoding.

A few warnings:
- you're required to use CODEC_FLAG_EMU_EDGE (in
AVCodecContext->flags), else you'll get weird borders around your
image. Assure linesize[0] == width.
- this doesn't work if your h264 picture has weird cropping parameters
(unlikely, but just to be sure)

HTH,
Ronald
_______________________________________________
libav-api mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-api

Reply via email to