GUAC-286: Actually write video output to file.
This commit is contained in:
parent
1ce39306cb
commit
f9f08627ff
@ -88,7 +88,7 @@ cairo_operator_t guacenc_display_cairo_operator(guac_composite_mode mask) {
|
|||||||
guacenc_display* guacenc_display_alloc(const char* path, const char* codec,
|
guacenc_display* guacenc_display_alloc(const char* path, const char* codec,
|
||||||
int width, int height, int bitrate) {
|
int width, int height, int bitrate) {
|
||||||
|
|
||||||
/* STUB: Prepare video encoding */
|
/* Prepare video encoding */
|
||||||
guacenc_video* video = guacenc_video_alloc(path, codec, width, height, bitrate);
|
guacenc_video* video = guacenc_video_alloc(path, codec, width, height, bitrate);
|
||||||
if (video == NULL)
|
if (video == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -43,7 +43,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
|||||||
if (codec == NULL) {
|
if (codec == NULL) {
|
||||||
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
|
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
|
||||||
codec_name);
|
codec_name);
|
||||||
return NULL;
|
goto fail_codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve encoding context */
|
/* Retrieve encoding context */
|
||||||
@ -51,7 +51,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
|||||||
if (context == NULL) {
|
if (context == NULL) {
|
||||||
guacenc_log(GUAC_LOG_ERROR, "Failed to allocate context for "
|
guacenc_log(GUAC_LOG_ERROR, "Failed to allocate context for "
|
||||||
"codec \"%s\".", codec_name);
|
"codec \"%s\".", codec_name);
|
||||||
return NULL;
|
goto fail_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init context with encoding parameters */
|
/* Init context with encoding parameters */
|
||||||
@ -66,13 +66,13 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
|||||||
/* Open codec for use */
|
/* Open codec for use */
|
||||||
if (avcodec_open2(context, codec, NULL) < 0) {
|
if (avcodec_open2(context, codec, NULL) < 0) {
|
||||||
guacenc_log(GUAC_LOG_ERROR, "Failed to open codec \"%s\".", codec_name);
|
guacenc_log(GUAC_LOG_ERROR, "Failed to open codec \"%s\".", codec_name);
|
||||||
goto fail_context;
|
goto fail_codec_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate corresponding frame */
|
/* Allocate corresponding frame */
|
||||||
AVFrame* frame = av_frame_alloc();
|
AVFrame* frame = av_frame_alloc();
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
goto fail_context;
|
goto fail_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy necessary data for frame from context */
|
/* Copy necessary data for frame from context */
|
||||||
@ -83,16 +83,25 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
|||||||
/* Allocate actual backing data for frame */
|
/* Allocate actual backing data for frame */
|
||||||
if (av_image_alloc(frame->data, frame->linesize, frame->width,
|
if (av_image_alloc(frame->data, frame->linesize, frame->width,
|
||||||
frame->height, frame->format, 32) < 0) {
|
frame->height, frame->format, 32) < 0) {
|
||||||
goto fail_frame;
|
goto fail_frame_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open output file */
|
||||||
|
FILE* output = fopen(path, "wb");
|
||||||
|
if (output == NULL) {
|
||||||
|
guacenc_log(GUAC_LOG_ERROR, "Failed to open output file \"%s\": %s",
|
||||||
|
path, strerror(errno));
|
||||||
|
goto fail_output_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate video structure */
|
/* Allocate video structure */
|
||||||
guacenc_video* video = malloc(sizeof(guacenc_video));
|
guacenc_video* video = malloc(sizeof(guacenc_video));
|
||||||
if (video == NULL) {
|
if (video == NULL) {
|
||||||
goto fail_frame_data;
|
goto fail_video;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init properties of video */
|
/* Init properties of video */
|
||||||
|
video->output = output;
|
||||||
video->context = context;
|
video->context = context;
|
||||||
video->next_frame = frame;
|
video->next_frame = frame;
|
||||||
video->width = width;
|
video->width = width;
|
||||||
@ -106,14 +115,21 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
|||||||
return video;
|
return video;
|
||||||
|
|
||||||
/* Free all allocated data in case of failure */
|
/* Free all allocated data in case of failure */
|
||||||
fail_frame_data:
|
fail_video:
|
||||||
|
fclose(output);
|
||||||
|
|
||||||
|
fail_output_file:
|
||||||
av_freep(&frame->data[0]);
|
av_freep(&frame->data[0]);
|
||||||
|
|
||||||
fail_frame:
|
fail_frame_data:
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
|
|
||||||
fail_context:
|
fail_frame:
|
||||||
|
fail_codec_open:
|
||||||
avcodec_free_context(&context);
|
avcodec_free_context(&context);
|
||||||
|
|
||||||
|
fail_context:
|
||||||
|
fail_codec:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -161,12 +177,26 @@ static int guacenc_video_write_frame(guacenc_video* video, AVFrame* frame) {
|
|||||||
|
|
||||||
/* Write corresponding data to file */
|
/* Write corresponding data to file */
|
||||||
if (got_data) {
|
if (got_data) {
|
||||||
|
|
||||||
|
/* Write data, logging any errors */
|
||||||
|
if (fwrite(packet.data, 1, packet.size, video->output) == 0) {
|
||||||
|
guacenc_log(GUAC_LOG_ERROR, "Unable to write frame "
|
||||||
|
"#%" PRId64 ": %s", video->next_pts, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data was written successfully */
|
||||||
guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": wrote %i bytes",
|
guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": wrote %i bytes",
|
||||||
video->next_pts, packet.size);
|
video->next_pts, packet.size);
|
||||||
/* TODO: Write frame to file */
|
|
||||||
av_packet_unref(&packet);
|
av_packet_unref(&packet);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Frame may have been queued for later writing / reordering */
|
||||||
|
else
|
||||||
|
guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": queued for later",
|
||||||
|
video->next_pts);
|
||||||
|
|
||||||
/* Update presentation timestamp for next frame */
|
/* Update presentation timestamp for next frame */
|
||||||
video->next_pts++;
|
video->next_pts++;
|
||||||
|
|
||||||
@ -245,6 +275,9 @@ int guacenc_video_free(guacenc_video* video) {
|
|||||||
retval = guacenc_video_write_frame(video, NULL);
|
retval = guacenc_video_write_frame(video, NULL);
|
||||||
} while (retval > 0);
|
} while (retval > 0);
|
||||||
|
|
||||||
|
/* File is now completely written */
|
||||||
|
fclose(video->output);
|
||||||
|
|
||||||
/* Free frame encoding data */
|
/* Free frame encoding data */
|
||||||
av_freep(&video->next_frame->data[0]);
|
av_freep(&video->next_frame->data[0]);
|
||||||
av_frame_free(&video->next_frame);
|
av_frame_free(&video->next_frame);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The framerate at which video should be encoded, in frames per second.
|
* The framerate at which video should be encoded, in frames per second.
|
||||||
@ -43,6 +44,11 @@
|
|||||||
*/
|
*/
|
||||||
typedef struct guacenc_video {
|
typedef struct guacenc_video {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output file stream.
|
||||||
|
*/
|
||||||
|
FILE* output;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The open encoding context from libavcodec, created for the codec
|
* The open encoding context from libavcodec, created for the codec
|
||||||
* specified when this guacenc_video was created.
|
* specified when this guacenc_video was created.
|
||||||
|
Loading…
Reference in New Issue
Block a user