Merge staging/1.2.0 changes back to master.
This commit is contained in:
commit
708769b4c3
22
configure.ac
22
configure.ac
@ -202,6 +202,24 @@ fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_AVCODEC], [test "x${have_libavcodec}" = "xyes"])
|
||||
|
||||
#
|
||||
# libavformat
|
||||
#
|
||||
|
||||
have_libavformat=disabled
|
||||
AC_ARG_WITH([libavformat],
|
||||
[AS_HELP_STRING([--with-libavformat],
|
||||
[use libavformat when encoding video @<:@default=check@:>@])],
|
||||
[].
|
||||
[with_libavformat=check])
|
||||
if test "x$with_libavformat" != "xno"
|
||||
then
|
||||
have_libavformat=yes
|
||||
PKG_CHECK_MODULES([AVFORMAT], [libavformat],, [have_libavformat=no]);
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_AVFORMAT], [test "x${have_libavformat}" = "xyes"])
|
||||
|
||||
#
|
||||
# libavutil
|
||||
#
|
||||
@ -998,7 +1016,8 @@ AC_ARG_ENABLE([guacenc],
|
||||
AM_CONDITIONAL([ENABLE_GUACENC], [test "x${enable_guacenc}" = "xyes" \
|
||||
-a "x${have_libavcodec}" = "xyes" \
|
||||
-a "x${have_libavutil}" = "xyes" \
|
||||
-a "x${have_libswscale}" = "xyes"])
|
||||
-a "x${have_libswscale}" = "xyes" \
|
||||
-a "x${have_libavformat}" = "xyes"])
|
||||
|
||||
#
|
||||
# guaclog
|
||||
@ -1091,6 +1110,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
|
||||
freerdp2 ............ ${have_freerdp2}
|
||||
pango ............... ${have_pango}
|
||||
libavcodec .......... ${have_libavcodec}
|
||||
libavformat.......... ${have_libavformat}
|
||||
libavutil ........... ${have_libavutil}
|
||||
libssh2 ............. ${have_libssh2}
|
||||
libssl .............. ${have_ssl}
|
||||
|
@ -90,6 +90,7 @@ endif
|
||||
guacenc_CFLAGS = \
|
||||
-Werror -Wall \
|
||||
@AVCODEC_CFLAGS@ \
|
||||
@AVFORMAT_CFLAGS@ \
|
||||
@AVUTIL_CFLAGS@ \
|
||||
@LIBGUAC_INCLUDE@ \
|
||||
@SWSCALE_CFLAGS@
|
||||
@ -99,6 +100,7 @@ guacenc_LDADD = \
|
||||
|
||||
guacenc_LDFLAGS = \
|
||||
@AVCODEC_LIBS@ \
|
||||
@AVFORMAT_LIBS@ \
|
||||
@AVUTIL_LIBS@ \
|
||||
@CAIRO_LIBS@ \
|
||||
@JPEG_LIBS@ \
|
||||
|
@ -51,8 +51,41 @@
|
||||
*/
|
||||
static int guacenc_write_packet(guacenc_video* video, void* data, int size) {
|
||||
|
||||
/* Write data, logging any errors */
|
||||
if (fwrite(data, 1, size, video->output) == 0) {
|
||||
int ret;
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,1,0)
|
||||
|
||||
AVPacket pkt;
|
||||
|
||||
/* Have to create a packet around the encoded data we have */
|
||||
av_init_packet(&pkt);
|
||||
|
||||
if (video->context->coded_frame->pts != AV_NOPTS_VALUE) {
|
||||
pkt.pts = av_rescale_q(video->context->coded_frame->pts,
|
||||
video->context->time_base,
|
||||
video->output_stream->time_base);
|
||||
}
|
||||
if (video->context->coded_frame->key_frame) {
|
||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||
}
|
||||
|
||||
pkt.data = data;
|
||||
pkt.size = size;
|
||||
pkt.stream_index = video->output_stream->index;
|
||||
ret = av_interleaved_write_frame(video->container_format_context, &pkt);
|
||||
|
||||
#else
|
||||
|
||||
/* We know data is already a packet if we're using a newer libavcodec */
|
||||
AVPacket* pkt = (AVPacket*) data;
|
||||
av_packet_rescale_ts(pkt, video->context->time_base, video->output_stream->time_base);
|
||||
pkt->stream_index = video->output_stream->index;
|
||||
ret = av_interleaved_write_frame(video->container_format_context, pkt);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
if (ret != 0) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Unable to write frame "
|
||||
"#%" PRId64 ": %s", video->next_pts, strerror(errno));
|
||||
return -1;
|
||||
@ -62,8 +95,7 @@ static int guacenc_write_packet(guacenc_video* video, void* data, int size) {
|
||||
guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": wrote %i bytes",
|
||||
video->next_pts, size);
|
||||
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
||||
@ -113,6 +145,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
||||
|
||||
/* For libavcodec < 57.37.100: input/output was not decoupled */
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,37,100)
|
||||
|
||||
/* Write frame to video */
|
||||
int got_data;
|
||||
if (avcodec_encode_video2(video->context, &packet, frame, &got_data) < 0) {
|
||||
@ -123,10 +156,12 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
||||
|
||||
/* Write corresponding data to file */
|
||||
if (got_data) {
|
||||
guacenc_write_packet(video, packet.data, packet.size);
|
||||
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);
|
||||
|
||||
@ -149,10 +184,11 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
||||
got_data = 1;
|
||||
|
||||
/* Attempt to write data to output file */
|
||||
guacenc_write_packet(video, packet.data, packet.size);
|
||||
guacenc_write_packet(video, (void*) &packet, packet.size);
|
||||
av_packet_unref(&packet);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Frame may have been queued for later writing / reordering */
|
||||
@ -165,3 +201,54 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
||||
#endif
|
||||
}
|
||||
|
||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
||||
int pix_fmt, AVRational time_base) {
|
||||
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 33, 100)
|
||||
stream->codec->bit_rate = bitrate;
|
||||
stream->codec->width = width;
|
||||
stream->codec->height = height;
|
||||
stream->codec->gop_size = gop_size;
|
||||
stream->codec->qmax = qmax;
|
||||
stream->codec->qmin = qmin;
|
||||
stream->codec->pix_fmt = pix_fmt;
|
||||
stream->codec->time_base = time_base;
|
||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 44, 100)
|
||||
stream->time_base = time_base;
|
||||
#endif
|
||||
return stream->codec;
|
||||
#else
|
||||
AVCodecContext* context = avcodec_alloc_context3(codec);
|
||||
if (context) {
|
||||
context->bit_rate = bitrate;
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->gop_size = gop_size;
|
||||
context->qmax = qmax;
|
||||
context->qmin = qmin;
|
||||
context->pix_fmt = pix_fmt;
|
||||
context->time_base = time_base;
|
||||
stream->time_base = time_base;
|
||||
}
|
||||
return context;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
||||
AVCodec *codec, AVDictionary **options,
|
||||
AVStream* stream) {
|
||||
|
||||
int ret = avcodec_open2(avcodec_context, codec, options);
|
||||
|
||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100)
|
||||
/* Copy stream parameters to the muxer */
|
||||
int codecpar_ret = avcodec_parameters_from_context(stream->codecpar, avcodec_context);
|
||||
if (codecpar_ret < 0)
|
||||
return codecpar_ret;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
@ -52,6 +52,16 @@
|
||||
#define av_packet_unref av_free_packet
|
||||
#endif
|
||||
|
||||
/* For libavcodec <= 56.41.100: Global header flag didn't have AV_ prefix.
|
||||
* Guacenc defines its own flag here to avoid conflicts with libavcodec
|
||||
* macros.
|
||||
*/
|
||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(56,41,100)
|
||||
#define GUACENC_FLAG_GLOBAL_HEADER CODEC_FLAG_GLOBAL_HEADER
|
||||
#else
|
||||
#define GUACENC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
|
||||
#endif
|
||||
|
||||
/* For libavutil < 51.42.0: AV_PIX_FMT_* was PIX_FMT_* */
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,42,0)
|
||||
#define AV_PIX_FMT_RGB32 PIX_FMT_RGB32
|
||||
@ -78,5 +88,78 @@
|
||||
*/
|
||||
int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame);
|
||||
|
||||
/**
|
||||
* Creates and sets up the AVCodecContext for the appropriate version of
|
||||
* libavformat installed. The AVCodecContext will be built, but the AVStream
|
||||
* will also be affected by having its time_base field set to the value passed
|
||||
* into this function.
|
||||
*
|
||||
* @param stream
|
||||
* The open AVStream.
|
||||
*
|
||||
* @param codec
|
||||
* The codec used on the AVStream.
|
||||
*
|
||||
* @param bitrate
|
||||
* The target bitrate for the encoded video
|
||||
*
|
||||
* @param width
|
||||
* The target width for the encoded video.
|
||||
*
|
||||
* @param height
|
||||
* The target height for the encoded video.
|
||||
*
|
||||
* @param gop_size
|
||||
* The size of the Group of Pictures.
|
||||
*
|
||||
* @param qmax
|
||||
* The max value of the quantizer.
|
||||
*
|
||||
* @param qmin
|
||||
* The min value of the quantizer.
|
||||
*
|
||||
* @param pix_fmt
|
||||
* The target pixel format for the encoded video.
|
||||
*
|
||||
* @param time_base
|
||||
* The target time base for the encoded video.
|
||||
*
|
||||
* @return
|
||||
* The pointer to the configured AVCodecContext.
|
||||
*
|
||||
*/
|
||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
||||
int pix_fmt, AVRational time_base);
|
||||
|
||||
/**
|
||||
* A wrapper for avcodec_open2(). Because libavformat ver 57.33.100 and greater
|
||||
* use stream->codecpar rather than stream->codec to handle information to the
|
||||
* codec, there needs to be an additional step in that version. So this
|
||||
* wrapper handles that. Otherwise, it's the same as avcodec_open2().
|
||||
*
|
||||
* @param avcodec_context
|
||||
* The context to initialize.
|
||||
*
|
||||
* @param codec
|
||||
* The codec to open this context for. If a non-NULL codec has been
|
||||
* previously passed to avcodec_alloc_context3() or for this context, then
|
||||
* this parameter MUST be either NULL or equal to the previously passed
|
||||
* codec.
|
||||
*
|
||||
* @param options
|
||||
* A dictionary filled with AVCodecContext and codec-private options. On
|
||||
* return this object will be filled with options that were not found.
|
||||
*
|
||||
* @param stream
|
||||
* The stream for the codec context.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, a negative value on error.
|
||||
*/
|
||||
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
||||
AVCodec *codec, AVDictionary **options,
|
||||
AVStream* stream);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "parse.h"
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
@ -80,6 +81,10 @@ int main(int argc, char* argv[]) {
|
||||
avcodec_register_all();
|
||||
#endif
|
||||
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
av_register_all();
|
||||
#endif
|
||||
|
||||
/* Track number of overall failures */
|
||||
int total_files = argc - optind;
|
||||
int failures = 0;
|
||||
|
@ -38,7 +38,7 @@ is essentially an implementation of a Guacamole client which accepts
|
||||
its input from files instead of a network connection, and renders directly to
|
||||
video instead of to the user's screen.
|
||||
.P
|
||||
Each \fIFILE\fR specified will be encoded as a raw MPEG-4 video stream to a new
|
||||
Each \fIFILE\fR specified will be encoded as MPEG-4 video to a new
|
||||
file named \fIFILE\fR.m4v, encoded according to the other options specified. By
|
||||
default, the output video will be \fI640\fRx\fI480\fR pixels, and will be saved
|
||||
with a bitrate of \fI2000000\fR bits per second (2 Mbps). These defaults can be
|
||||
|
@ -25,6 +25,9 @@
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#ifndef AVFORMAT_AVFORMAT_H
|
||||
#include <libavformat/avformat.h>
|
||||
#endif
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
@ -43,6 +46,21 @@
|
||||
guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
int width, int height, int bitrate) {
|
||||
|
||||
AVOutputFormat *container_format;
|
||||
AVFormatContext *container_format_context;
|
||||
AVStream *video_stream;
|
||||
int ret;
|
||||
int failed_header = 0;
|
||||
|
||||
/* allocate the output media context */
|
||||
avformat_alloc_output_context2(&container_format_context, NULL, NULL, path);
|
||||
if (container_format_context == NULL) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Failed to determine container from output file name\n");
|
||||
goto fail_codec;
|
||||
}
|
||||
|
||||
container_format = container_format_context->oformat;
|
||||
|
||||
/* Pull codec based on name */
|
||||
AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
|
||||
if (codec == NULL) {
|
||||
@ -51,25 +69,35 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
goto fail_codec;
|
||||
}
|
||||
|
||||
/* create stream */
|
||||
video_stream = NULL;
|
||||
video_stream = avformat_new_stream(container_format_context, codec);
|
||||
if (video_stream == NULL) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Could not allocate encoder stream. Cannot continue.\n");
|
||||
goto fail_format_context;
|
||||
}
|
||||
video_stream->id = container_format_context->nb_streams - 1;
|
||||
|
||||
/* Retrieve encoding context */
|
||||
AVCodecContext* context = avcodec_alloc_context3(codec);
|
||||
if (context == NULL) {
|
||||
AVCodecContext* avcodec_context =
|
||||
guacenc_build_avcodeccontext(video_stream, codec, bitrate, width,
|
||||
height, /*gop size*/ 10, /*qmax*/ 31, /*qmin*/ 2,
|
||||
/*pix fmt*/ AV_PIX_FMT_YUV420P,
|
||||
/*time base*/ (AVRational) { 1, GUACENC_VIDEO_FRAMERATE });
|
||||
|
||||
if (avcodec_context == NULL) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Failed to allocate context for "
|
||||
"codec \"%s\".", codec_name);
|
||||
goto fail_context;
|
||||
}
|
||||
|
||||
/* Init context with encoding parameters */
|
||||
context->bit_rate = bitrate;
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->time_base = (AVRational) { 1, GUACENC_VIDEO_FRAMERATE };
|
||||
context->gop_size = 10;
|
||||
context->max_b_frames = 1;
|
||||
context->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||
/* If format needs global headers, write them */
|
||||
if (container_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
avcodec_context->flags |= GUACENC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
|
||||
/* Open codec for use */
|
||||
if (avcodec_open2(context, codec, NULL) < 0) {
|
||||
if (guacenc_open_avcodec(avcodec_context, codec, NULL, video_stream) < 0) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Failed to open codec \"%s\".", codec_name);
|
||||
goto fail_codec_open;
|
||||
}
|
||||
@ -81,9 +109,9 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
}
|
||||
|
||||
/* Copy necessary data for frame from context */
|
||||
frame->format = context->pix_fmt;
|
||||
frame->width = context->width;
|
||||
frame->height = context->height;
|
||||
frame->format = avcodec_context->pix_fmt;
|
||||
frame->width = avcodec_context->width;
|
||||
frame->height = avcodec_context->height;
|
||||
|
||||
/* Allocate actual backing data for frame */
|
||||
if (av_image_alloc(frame->data, frame->linesize, frame->width,
|
||||
@ -91,31 +119,32 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
goto fail_frame_data;
|
||||
}
|
||||
|
||||
/* Open output file */
|
||||
int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Failed to open output file \"%s\": %s",
|
||||
path, strerror(errno));
|
||||
goto fail_output_fd;
|
||||
/* Open output file, if the container needs it */
|
||||
if (!(container_format->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&container_format_context->pb, path, AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Error occurred while opening output file.\n");
|
||||
goto fail_output_avio;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create stream for output file */
|
||||
FILE* output = fdopen(fd, "wb");
|
||||
if (output == NULL) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Failed to allocate stream for output "
|
||||
"file \"%s\": %s", path, strerror(errno));
|
||||
goto fail_output_file;
|
||||
/* write the stream header, if needed */
|
||||
ret = avformat_write_header(container_format_context, NULL);
|
||||
if (ret < 0) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Error occurred while writing output file header.\n");
|
||||
failed_header = true;
|
||||
}
|
||||
|
||||
/* Allocate video structure */
|
||||
guacenc_video* video = malloc(sizeof(guacenc_video));
|
||||
if (video == NULL) {
|
||||
goto fail_video;
|
||||
goto fail_output_file;
|
||||
}
|
||||
|
||||
/* Init properties of video */
|
||||
video->output = output;
|
||||
video->context = context;
|
||||
video->output_stream = video_stream;
|
||||
video->context = avcodec_context;
|
||||
video->container_format_context = container_format_context;
|
||||
video->next_frame = frame;
|
||||
video->width = width;
|
||||
video->height = height;
|
||||
@ -125,16 +154,24 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
video->last_timestamp = 0;
|
||||
video->next_pts = 0;
|
||||
|
||||
if (failed_header) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "An incompatible codec/container "
|
||||
"combination was specified. Cannot encode.\n");
|
||||
goto fail_output_file;
|
||||
}
|
||||
|
||||
return video;
|
||||
|
||||
/* Free all allocated data in case of failure */
|
||||
fail_video:
|
||||
fclose(output);
|
||||
|
||||
fail_output_file:
|
||||
close(fd);
|
||||
avio_close(container_format_context->pb);
|
||||
/* delete the file that was created if it was actually created */
|
||||
if (access(path, F_OK) != -1) {
|
||||
remove(path);
|
||||
}
|
||||
|
||||
fail_output_fd:
|
||||
fail_output_avio:
|
||||
av_freep(&frame->data[0]);
|
||||
|
||||
fail_frame_data:
|
||||
@ -142,7 +179,13 @@ fail_frame_data:
|
||||
|
||||
fail_frame:
|
||||
fail_codec_open:
|
||||
avcodec_free_context(&context);
|
||||
avcodec_free_context(&avcodec_context);
|
||||
|
||||
fail_format_context:
|
||||
/* failing to write the container implicitly frees the context */
|
||||
if (!failed_header) {
|
||||
avformat_free_context(container_format_context);
|
||||
}
|
||||
|
||||
fail_context:
|
||||
fail_codec:
|
||||
@ -435,26 +478,34 @@ int guacenc_video_free(guacenc_video* video) {
|
||||
/* Write final frame */
|
||||
guacenc_video_flush_frame(video);
|
||||
|
||||
/* Init video packet for final flush of encoded data */
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
/* Flush any unwritten frames */
|
||||
int retval;
|
||||
do {
|
||||
retval = guacenc_video_write_frame(video, NULL);
|
||||
} while (retval > 0);
|
||||
|
||||
/* write trailer, if needed */
|
||||
if (video->container_format_context != NULL &&
|
||||
video->output_stream != NULL) {
|
||||
guacenc_log(GUAC_LOG_DEBUG, "Writing trailer: %d\n",
|
||||
av_write_trailer(video->container_format_context) == 0 ?
|
||||
"success" : "failure");
|
||||
}
|
||||
|
||||
/* File is now completely written */
|
||||
fclose(video->output);
|
||||
if (video->container_format_context != NULL) {
|
||||
avio_close(video->container_format_context->pb);
|
||||
}
|
||||
|
||||
/* Free frame encoding data */
|
||||
av_freep(&video->next_frame->data[0]);
|
||||
av_frame_free(&video->next_frame);
|
||||
|
||||
/* Clean up encoding context */
|
||||
if (video->context != NULL) {
|
||||
avcodec_close(video->context);
|
||||
avcodec_free_context(&(video->context));
|
||||
}
|
||||
|
||||
free(video);
|
||||
return 0;
|
||||
|
@ -26,6 +26,14 @@
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
#ifndef AVCODEC_AVCODEC_H
|
||||
#include <libavcodec/avcodec.h>
|
||||
#endif
|
||||
|
||||
#ifndef AVFORMAT_AVFORMAT_H
|
||||
#include <libavformat/avformat.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@ -42,9 +50,11 @@
|
||||
typedef struct guacenc_video {
|
||||
|
||||
/**
|
||||
* Output file stream.
|
||||
* AVStream for video output.
|
||||
* Frames sent to this stream are written into
|
||||
* the output file in the specified container format.
|
||||
*/
|
||||
FILE* output;
|
||||
AVStream* output_stream;
|
||||
|
||||
/**
|
||||
* The open encoding context from libavcodec, created for the codec
|
||||
@ -52,6 +62,12 @@ typedef struct guacenc_video {
|
||||
*/
|
||||
AVCodecContext* context;
|
||||
|
||||
/**
|
||||
* The open format context from libavformat, created for the file
|
||||
* container specified when this guacenc_video was created.
|
||||
*/
|
||||
AVFormatContext* container_format_context;
|
||||
|
||||
/**
|
||||
* The width of the video, in pixels.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user