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?
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);