int guacenc_avcodec_encode_video()

in src/guacenc/ffmpeg-compat.c [101:214]


int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {

/* For libavcodec < 54.1.0: packets were handled as raw malloc'd buffers */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,1,0)

    AVCodecContext* context = video->context;

    /* Calculate appropriate buffer size */
    int length = FF_MIN_BUFFER_SIZE + 12 * context->width * context->height;

    /* Allocate space for output */
    uint8_t* data = malloc(length);
    if (data == NULL)
        return -1;

    /* Encode packet of video data */
    int used = avcodec_encode_video(context, data, length, frame);
    if (used < 0) {
        guacenc_log(GUAC_LOG_WARNING, "Error encoding frame #%" PRId64,
                video->next_pts);
        free(data);
        return -1;
    }

    /* Report if no data needs to be written */
    if (used == 0) {
        free(data);
        return 0;
    }

    /* Write data, logging any errors */
    guacenc_write_packet(video, data, used);
    free(data);
    return 1;

#else

/* For libavcodec < 57.37.100: input/output was not decoupled and static
 * allocation of AVPacket was supported.
 *
 * NOTE: Since dynamic allocation of AVPacket was added before this point (in
 * 57.12.100) and static allocation was deprecated later (in 58.133.100), it is
 * convenient to tie static vs. dynamic allocation to the old vs. new I/O
 * mechanism and avoid further complicating the version comparison logic. */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 37, 100)

    /* Init video packet */
    AVPacket packet;
    av_init_packet(&packet);

    /* Request that encoder allocate data for packet */
    packet.data = NULL;
    packet.size = 0;

    /* Write frame to video */
    int got_data;
    if (avcodec_encode_video2(video->context, &packet, frame, &got_data) < 0) {
        guacenc_log(GUAC_LOG_WARNING, "Error encoding frame #%" PRId64,
                video->next_pts);
        return -1;
    }

    /* Write corresponding data to file */
    if (got_data) {
        guacenc_write_packet(video, (void*) &packet, packet.size);
        av_packet_unref(&packet);
    }

#else

    /* Write frame to video */
    int result = avcodec_send_frame(video->context, frame);

    /* Stop once encoded has been flushed */
    if (result == AVERROR_EOF)
        return 0;

    /* Abort on error */
    else if (result < 0) {
        guacenc_log(GUAC_LOG_WARNING, "Error encoding frame #%" PRId64,
                video->next_pts);
        return -1;
    }

    AVPacket* packet = av_packet_alloc();
    if (packet == NULL)
        return -1;

    /* Flush all available packets */
    int got_data = 0;
    while (avcodec_receive_packet(video->context, packet) == 0) {

        /* Data was received */
        got_data = 1;

        /* Attempt to write data to output file */
        guacenc_write_packet(video, (void*) packet, packet->size);
        av_packet_unref(packet);

    }

    av_packet_free(&packet);

#endif

    /* Frame may have been queued for later writing / reordering */
    if (!got_data)
        guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": queued for later",
                video->next_pts);

    return got_data;

#endif
}