ffmpegcairoyuvlibavswscale

sws_scale generates malformed video


I have to encode a series of frames from CAIRO_FORMAT_ARGB32 to AV_PIX_FMT_YUV420P with sws_scale. From the ffmpeg docs I came to know the AV equivalent of the source format is AV_PIX_FMT_ARGB so here is my code:

 // Set up conversion context
    img->sws_ctx = sws_getCachedContext(
        img->sws_ctx,
        img->video_size[0],
        img->video_size[1],
        AV_PIX_FMT_ARGB,
        img->video_size[0],
        img->video_size[1],
        AV_PIX_FMT_YUV420P,
        SWS_BILINEAR,
        NULL,
        NULL,
        NULL);

    width  = cairo_image_surface_get_width( surface );
    height = cairo_image_surface_get_height( surface );
    stride = cairo_image_surface_get_stride( surface );
    pix    = cairo_image_surface_get_data( surface );
    const int in_linesize[1] = { stride };
    
    sws_scale(  img->sws_ctx, (const uint8_t * const *) &pix, in_linesize, 0,
                img->video_size[1], img->video_frame->data, img->video_frame->linesize);
    img->video_frame->pts++;

Sadly the video doesn't play and VLC shows a bunch of these useless messages:

[h264 @ 0x7f6ce0cbc1c0] mmco: unref short failure
[h264 @ 0x7f6ce0c39a80] co located POCs unavailable
[h264 @ 0x7f6ce0c82800] co located POCs unavailable
[h264 @ 0x7f6ce0c9f400] mmco: unref short failure

The encoding process runs just fine. I also tried with const int in_linesize[1] = { 3 * width }; Where am I wrong?


Solution

  • Ok, for anyone interested here is the correct code, an out frame must be allocated first and pixel data has to be copied into it:

    // Set up conversion context
    img->sws_ctx = sws_getContext(
        img->video_size[0],
        img->video_size[1],
        AV_PIX_FMT_BGRA,
        img->video_size[0],
        img->video_size[1],
        img->codec_context->pix_fmt,
        SWS_BICUBIC,
        NULL,
        NULL,
        NULL);
    memcpy(img->video_frame->data[0], pix, width * height * 4);
    
     // Allocate the output frame
    AVFrame *out_frame = av_frame_alloc();
    out_frame->format = img->codec_context->pix_fmt;
    out_frame->width = width;
    out_frame->height = height;
    av_frame_get_buffer(out_frame, 0);
    sws_scale(img->sws_ctx, (const uint8_t * const*)img->video_frame->data, img->video_frame->linesize, 0,
                img->video_size[1], out_frame->data, out_frame->linesize);