libx264 Input picture width (640) is greater than stride (0)

Viewed 178

I'm trying to encode a series of Cairo surfaces by using libav. Here I initialize AV stuff:

AVStream* video_stream;
    AVCodec* vcodec;
    gint ret;
  
    /* Setup video container */
    avformat_alloc_output_context2(&img->video_format_context, NULL, NULL, filename);
    if (img->video_format_context == NULL)
    {
        img_message(img, TRUE, _("Failed to find a suitable container for %s\n"),filename);
        return FALSE;
    }
    ret = avio_open(&img->video_format_context->pb, filename, AVIO_FLAG_WRITE);
    if (ret < 0)
    {
        img_message(img, TRUE, _("Couldn't write output file %s\n"),filename);
        return FALSE;
    }
    /* Setup video codec */
    vcodec = avcodec_find_encoder(codec_id);
    if (!vcodec)
    {
        img_message(img, TRUE, _("Couldn't find any encoder for %s\n"),filename);
        return FALSE;
    }
    /* Create video stream */
    video_stream = avformat_new_stream(img->video_format_context, vcodec);
    video_stream->id = 0;
    if (! video_stream)
    {
        img_message(img, TRUE, _("Couldn't not allocate video stream\n"));
        return FALSE;
    }
    /* Allocate video encoding context */
    img->codec_context = avcodec_alloc_context3(vcodec);
    if (! img->codec_context)
    {
        img_message(img, TRUE, _("Couldn't allocate video enconding context\n"));
        return FALSE;
    }
    /* Setup video enconding context parameters */
    img->codec_context->codec_id = codec_id;
    img->codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
    img->codec_context->width  = img->video_size[0];
    img->codec_context->height = img->video_size[1];
    img->codec_context->sample_aspect_ratio = (struct AVRational) {1, 1};
    img->codec_context->pix_fmt = vcodec->pix_fmts[0];
    img->codec_context->framerate = av_d2q(frame_rate, INT_MAX);

    if (codec_id == AV_CODEC_ID_VP8 || codec_id == AV_CODEC_ID_VP9 || codec_id == AV_CODEC_ID_THEORA || codec_id == AV_CODEC_ID_FLV1 ||
        AV_CODEC_ID_MPEG1VIDEO || codec_id == AV_CODEC_ID_MPEG2VIDEO)
        img->codec_context->bit_rate = round(bitrate_crf * 1000000);

    img->codec_context->time_base = av_inv_q(img->codec_context->framerate);
    video_stream->time_base = img->codec_context->time_base;

    if (img->video_format_context->oformat->flags & AVFMT_GLOBALHEADER)
        img->codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    /* Some codecs require the CRF value */
    if (codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_H265)
    {
        gchar *crf = g_strdup_printf("%i", bitrate_crf);
        av_opt_set(img->codec_context->priv_data, "crf", crf, AV_OPT_SEARCH_CHILDREN);
        g_free(crf);
    }
    /* Set exporting stage to be multithreaded */
    AVDictionary* opts = NULL;
    av_dict_set(&opts, "threads", "auto", 0);

    /* Open video encoder */
    ret = avcodec_open2(img->codec_context, vcodec, &opts);
    if (ret < 0)
    {
        img_message(img, TRUE, _("Failed to open the video encoder\n"));
        return FALSE;
    }
    /* Copy video encoder parameters to output stream */
    ret = avcodec_parameters_from_context(video_stream->codecpar, img->codec_context);
    if (ret < 0)
    {
        img_message(img, TRUE, _("Failed to copy video encoder parameters to output stream\n"));
        return FALSE;
    }
    
    /* AVFRAME stuff */
    img->video_frame = av_frame_alloc();
    img->video_frame->format = AV_PIX_FMT_RGBA;
    img->video_frame->width  = img->video_size[0];
    img->video_frame->height = img->video_size[1];

    av_frame_make_writable(img->video_frame);
    
    ret = av_frame_get_buffer(img->video_frame, 1);
    if (ret < 0)
        img_message(img,TRUE, _("Could not allocate the video frame data\n"));
    img->video_packet = av_packet_alloc();

And here I called repeatedly (the function is called somewehere else) av_send_frame() but it throws the error in the subject:

gint    width, height, stride, row, col, offset;
    uint8_t  *pix;

    /* Image info and pixel data */
    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 );

    for( row = 0; row < height; row++ )
    {
        for( col = 0; col < width; col++ )
        {
            offset = 3 * col + row * img->video_frame->linesize[0];
            img->video_frame->data[0][offset + 0] = pix[0];
            img->video_frame->data[0][offset + 1] = pix[1];
            img->video_frame->data[0][offset + 2] = pix[2];
        }
    }
    img_export_encode_av_frame(img->video_frame, img->video_format_context, img->codec_context, img->video_packet);
    return TRUE;
}

void img_export_encode_av_frame(AVFrame *frame, AVFormatContext *fmt, AVCodecContext *ctx, AVPacket *pkt)
{
     gint ret;
    
    /* send the frame to the encoder */
    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0)
        g_print("Error sending a frame for encoding\n");

    while (ret >= 0)
    {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0)
            g_print("Error during encoding\n");
            
        av_interleaved_write_frame(fmt, pkt);
        av_packet_unref(pkt);
    }
}

I googled here also but with no luck. It seems I'm the only one to encode a cairo surface. Grepping the error message in ffmpeg sources didn't help. How do I set the stride? I read ffmpeg does it for me once I allocate the buffer for the frame but in my case it seems it doesn't. Where am I wrong?

0 Answers
Related