On Mon, 14 Apr 2014 13:20:31 +0300
Ondřej Perutka <[email protected]> wrote:

> 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;
> }

You probably do this to create a guard page, but normally you should
use av_frame_get_buffer() to allocate an image.

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

And if you use av_frame_get_buffer(), av_frame_free() will actually
free the image.

> 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;
> }
> 

I can reproduce your problems, but didn't find the cause. The following
code works just fine, so I assume the avpicture_ crap is to blame, and
the fact that you try aliasing AVFrame with AVPicture (which I think is
allowed, but probably still causes problems). I'd suggest you use
AVFrames natively instead.

The following code works, and passes valgrind without errors:

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

AVFrame *alloc_frame(int w, int h, int pf) {
    AVFrame *result = av_frame_alloc();
    result->format = pf;
    result->width = w;
    result->height = h;
    av_frame_get_buffer(result, 32); // misses error check
    return result;
}

void free_frame(AVFrame** frame) {
    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;
    int p, y;

    AVFrame *f1 = alloc_frame(srcW, srcH, srcPF);
    // avoid valgrind errors (YUV420P specific code)
    for (p = 0; p < 3; p++) {
        for (y = 0; y < f1->height / (p ? 2 : 1); y++)
            memset(f1->data[p] + f1->linesize[p] * y, 0, f1->linesize[p]);
    }

    int n = 1000;

    AVFrame *f2;
    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 */
        f2 = alloc_frame(dstW, dstH, dstPF);
        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(&f2);
    }

    free_frame(&f1);

    return 0;
}


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

Reply via email to