Sorry, the attachment was probably filtered out by the mailing list. Here
is the code:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "libswscale/swscale.h"
#include "libavutil/pixfmt.h"
#include "libavutil/frame.h"
#include "libavcodec/avcodec.h"
#include <sys/mman.h>

#define PADDING 8
#define PAGE_SIZE 0x1000
#define PAGE_MASK (PAGE_SIZE - 1)

void * alloc_frame(int w, int h, int pf, AVFrame **frame) {
    /* get required buffer size + PADDING */
    int size = avpicture_get_size(pf, w, h) + PADDING;
    /* allocate buffer (make some space for additional locked page) */
    uint8_t *data = av_malloc(size + 2 * PAGE_SIZE);
    /* get address of the first byte after the padding */
    uint8_t *nextByte = data + size;
    /* compute offset for the buffer alignment */
    unsigned int offset = PAGE_SIZE - ((uint64_t)nextByte & PAGE_MASK);
    AVFrame *result;

    /* get address of the next page after the padding */
    uint8_t *nextPage = (uint64_t)nextByte & ~PAGE_MASK;
    if (((uint64_t)nextByte & PAGE_MASK) != 0)
        nextPage += PAGE_SIZE;

    /* lock the next page */
    mprotect(nextPage, PAGE_SIZE, PROT_NONE);

    /* allocate a new frame and fill it with aligned data */
    result = av_frame_alloc();
    avpicture_fill(result, data + offset, pf, w, h);

    /* print some info */
    printf("buffer: [0x%016lx, 0x%016lx]\n",
        (uint64_t)(data + offset),                      /* first byte */
        (uint64_t)(data + offset + size - PADDING));    /* last byte + 1 */
    printf("trap address: 0x%016lx\n", (uint64_t)(nextPage));
    printf("img size: [%d, %d]\n", w, h);

    *frame = result;
    return data;
}

void free_frame(void *buffer, AVFrame** frame) {
    av_free(buffer);
    av_frame_free(frame);
}

int main(void) {
    int srcW = 1280;
    int srcH = 536;
    int dstW, dstH;
    int srcPF = AV_PIX_FMT_YUV420P;
    int dstPF = AV_PIX_FMT_BGRA;

    AVFrame *f1;
    void *buffer1 = alloc_frame(srcW, srcH, srcPF, &f1);

    int n = 1000;

    AVFrame *f2;
    void *buffer2;
    struct SwsContext *sc;

    srand(time(NULL));

    while (n-- > 0) {
        /* make some random output dimensions */
        dstW = 736 + (rand() % 400) - 200;
        dstH = 308 + (rand() % 400) - 200;

        /* allocate output frame and scale context */
        buffer2 = alloc_frame(dstW, dstH, dstPF, &f2);
        sc = sws_getCachedContext(NULL, srcW, srcH, srcPF,
            dstW, dstH, dstPF, SWS_BICUBIC, NULL, NULL, NULL);

        sws_scale(sc, f1->data, f1->linesize, 0, srcH,
            f2->data, f2->linesize);

        /* free the scale context and the output frame */
        sws_freeContext(sc);
        free_frame(buffer2, &f2);
    }

    free_frame(buffer1, &f1);

    return 0;
}



2014-04-14 11:28 GMT+03:00 wm4 <[email protected]>:

> On Mon, 14 Apr 2014 03:23:33 +0300
> Ondřej Perutka <[email protected]> wrote:
>
> > Hello,
> >
> > I have a problem with libswscale. I was getting segfaults on attempt to
> > free data buffer of an AVFrame (note: the AVFrame was not ref. counted, I
> > did the allocation of the data buffer using av_malloc). The problem was
> > that the size of the next block after the data buffer was always
> rewritten,
> > so the free() was complaining.
> >
> > I decided to allocate a bigger buffer (by one page + some padding) and
> lock
> > the next page after the buffer using mprotect(). So the memory looked
> like
> > this:
> >
> > ------------------------------------------
> > ... | BUFFER | PADDING | LOCKED PAGE | ...
> > ------------------------------------------
> >
> > I tried several sizes of padding (0B, 8B, 100B, 4kB and 8kB), these are
> > addresses where the process received segfault because of accessing the
> > locked page:
> >
> > yuv2rgbx32_X_c+0x1dd (0B padding)
> > yuv2rgb32_X_mmxext+0x2e7 (8B padding)
> > yuv2rgb32_X_mmxext+0x2e7 (100B padding)
> > yuv2rgbx32_X_c+0x1ce (4kB padding)
> > yuv2rgbx32_X_c+0x1ce (8kB padding)
> >
> > These are the scale context parameters:
> >
> > src width: 1280
> > src height: 536
> > src pixel format: yuv420p
> > dst pixel format: bgra
> >
> > The output picture size was always different (because of resizable
> window)
> > but there was no segfault for the initial picture size 736x308.
> >
> > I used the following Libav functions:
> >
> > av_frame_alloc() to allocate the output frame
> > avpicture_get_size() to get size of the buffer
> > av_malloc() to allocate the buffer
> > avpicture_fill() to set the buffer into the output frame
> > sws_getCachedContext() to allocate the scale context
> > sws_scale() for scaling
>
> Using these avpicture functions sounds fishy. Your code might still be
> correct regardless, though.
>
> > Used Libav version: 10 (from tarball)
> >
> > The problem always showed up after several reallocations of the scale
> > context and the output AVFrame. There is no problem with older versions
> of
> > Libav.
> >
> > Attached is a sample code. Is there something I'm doing wrong?
>
> Forgot to actually attach the code?
> _______________________________________________
> libav-api mailing list
> [email protected]
> https://lists.libav.org/mailman/listinfo/libav-api
_______________________________________________
libav-api mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-api

Reply via email to