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