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