32 #include <libavcodec/avcodec.h>
33 #include <libavformat/avformat.h>
34 #include <libswscale/swscale.h>
37 #define VNC_PIX_FMT AV_PIX_FMT_RGB565
38 #define OUTPUT_PIX_FMT AV_PIX_FMT_YUV420P
40 static int write_packet(AVFormatContext *
oc,
const AVRational *time_base, AVStream *st, AVPacket *pkt)
43 av_packet_rescale_ts(pkt, *time_base, st->time_base);
44 pkt->stream_index = st->index;
46 return av_interleaved_write_frame(
oc, pkt);
60 struct SwsContext *
sws;
65 enum AVCodecID codec_id, int64_t br,
int sr,
int w,
int h)
70 ost->
codec = avcodec_find_encoder(codec_id);
72 fprintf(stderr,
"Could not find encoder for '%s'\n",
73 avcodec_get_name(codec_id));
76 if (ost->
codec->type != AVMEDIA_TYPE_VIDEO) {
77 fprintf(stderr,
"Encoder for '%s' does not seem to be for video.\n",
78 avcodec_get_name(codec_id));
81 ost->
enc = avcodec_alloc_context3(ost->
codec);
83 fprintf(stderr,
"Could not alloc an encoding context\n");
88 ost->
enc->codec_id = codec_id;
89 ost->
enc->bit_rate = br;
91 ost->
enc->width = w + (w % 2);
92 ost->
enc->height = h + (h % 2);
97 ost->
enc->time_base = (AVRational){ 1, sr };
98 ost->
enc->gop_size = 12;
100 if (ost->
enc->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
104 ost->
enc->mb_decision = 2;
107 ost->
st = avformat_new_stream(
oc, ost->
codec);
109 fprintf(stderr,
"Could not allocate stream\n");
110 avcodec_free_context(&(ost->
enc));
113 ost->
st->id =
oc->nb_streams-1;
114 ost->
st->time_base = ost->
enc->time_base;
118 if (
oc->oformat->flags & AVFMT_GLOBALHEADER)
119 ost->
enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
129 picture = av_frame_alloc();
133 picture->format = pix_fmt;
134 picture->width =
width;
137 ret = av_frame_get_buffer(picture, 64);
139 fprintf(stderr,
"Could not allocate frame data.\n");
140 av_frame_free(&picture);
150 ret = avcodec_open2(ost->
enc, ost->
codec, NULL);
152 fprintf(stderr,
"Could not open video codec: %s\n", av_err2str(ret));
156 ret = avcodec_parameters_from_context(ost->
st->codecpar, ost->
enc);
158 fprintf(stderr,
"Could not copy the stream parameters.\n");
164 fprintf(stderr,
"Could not allocate video frame\n");
175 fprintf(stderr,
"Could not allocate temporary picture\n");
176 av_frame_free(&(ost->
frame));
179 ost->
sws = sws_getCachedContext(ost->
sws, ost->
enc->width, ost->
enc->height,
VNC_PIX_FMT, ost->
enc->width, ost->
enc->height, ost->
enc->pix_fmt, 0, NULL, NULL, NULL);
181 fprintf(stderr,
"Could not get sws context\n");
182 av_frame_free(&(ost->
frame));
198 AVPacket pkt = { 0 };
199 if (pts <= ost->pts)
return 0;
202 sws_scale(ost->
sws, (
const uint8_t *
const *)ost->
tmp_frame->data,
209 ret = avcodec_send_frame(ost->
enc, ost->
frame);
211 fprintf(stderr,
"Error sending video frame to encoder: %s\n", av_err2str(ret));
216 for (ret = avcodec_receive_packet(ost->
enc, &pkt); ret == 0; ret = avcodec_receive_packet(ost->
enc, &pkt)) {
217 ret2 = write_packet(
oc, &(ost->
enc->time_base), ost->
st, &pkt);
219 fprintf(stderr,
"Error while writing video frame: %s\n", av_err2str(ret2));
223 if (ret2 < 0)
return ret2;
224 if (!(ret == AVERROR(EAGAIN)))
return ret;
234 AVPacket pkt = { 0 };
237 ret = avcodec_send_frame(ost->
enc, NULL);
239 fprintf(stderr,
"Error sending final video frame to encoder: %s\n", av_err2str(ret));
244 for (ret = avcodec_receive_packet(ost->
enc, &pkt); ret == 0; ret = avcodec_receive_packet(ost->
enc, &pkt)) {
245 ret2 = write_packet(
oc, &(ost->
enc->time_base), ost->
st, &pkt);
247 fprintf(stderr,
"Error while writing final video frame: %s\n", av_err2str(ret2));
251 if (ret2 < 0)
return ret2;
252 if (!(ret == AVERROR(EOF)))
return ret;
258 avcodec_free_context(&(ost->
enc));
259 av_frame_free(&(ost->
frame));
261 sws_freeContext(ost->
sws); ost->
sws = NULL;
273 ret = avformat_alloc_output_context2(&
oc, NULL, NULL,
filename);
275 fprintf(stderr,
"Warning: Could not deduce output format from file extension: using MP4.\n");
276 ret = avformat_alloc_output_context2(&
oc, NULL,
"mp4",
filename);
279 fprintf(stderr,
"Error: Could not allocate media context: %s.\n", av_err2str(ret));
284 if (
oc->oformat->video_codec != AV_CODEC_ID_NONE) {
290 fprintf(stderr,
"Error: chosen output format does not have a video codec, or error %i\n", ret);
291 avformat_free_context(
oc);
oc = NULL;
298 fprintf(stderr,
"Error: error opening video codec, error %i\n", ret);
300 avformat_free_context(
oc);
oc = NULL;
305 if (!(
oc->oformat->flags & AVFMT_NOFILE)) {
306 ret = avio_open(&
oc->pb,
filename, AVIO_FLAG_WRITE);
308 fprintf(stderr,
"Could not open '%s': %s\n",
filename,
311 avformat_free_context(
oc);
oc = NULL;
317 ret = avformat_write_header(
oc, NULL);
319 fprintf(stderr,
"Error occurred when writing to output file: %s\n",
321 if (!(
oc->oformat->flags & AVFMT_NOFILE))
322 avio_closep(&
oc->pb);
324 avformat_free_context(
oc);
oc = NULL;
331 AVFormatContext *
oc = *ocp;
340 av_write_trailer(
oc);
345 if (!(
oc->oformat->flags & AVFMT_NOFILE))
347 avio_closep(&
oc->pb);
350 avformat_free_context(
oc);
361 AVFormatContext *
oc = NULL;
365 struct timespec start_time,
cur_time;
374 time_t ds =
cur_time->tv_sec - start_time->tv_sec;
375 long dns =
cur_time->tv_nsec - start_time->tv_nsec;
377 int64_t dt = (int64_t)ds*(int64_t)1000000+(int64_t)dns/(int64_t)1000;
379 int64_t rv = (((int64_t)
framerate)*dt + (int64_t)500000) / (int64_t)(1000000);
410 int main(
int argc,
char **argv)
421 #if LIBAVUTIL_VERSION_MAJOR < 56
426 for(i=1;i<argc;i++) {
428 if(argc>i+1 && !strcmp(
"-o",argv[i])) {
431 }
else if(argc>i+1 && !strcmp(
"-t",argv[i])) {
433 if (max_time < 10 || max_time > 100000000) {
434 fprintf(stderr,
"Warning: Nonsensical time-per-file %li, resetting to default.\n",
max_time);
442 memmove(argv+i,argv+j,(argc-i)*
sizeof(
char*));
449 fprintf(stderr,
"Warning: No filename specified. Using output.mp4\n");
457 printf(
"usage: %s [-o output_file] [-t seconds-per-file] server:port\n", argv[0]);
462 clock_gettime(CLOCK_MONOTONIC, &start_time);
472 clock_gettime(CLOCK_MONOTONIC, &
cur_time);
rfbClient * rfbGetClient(int bitsPerSample, int samplesPerPixel, int bytesPerPixel)
Allocates and returns a pointer to an rfbClient structure.
int WaitForMessage(rfbClient *client, unsigned int usecs)
Waits for an RFB message to arrive from the server.
rfbBool HandleRFBServerMessage(rfbClient *client)
Handles messages from the RFB server.
rfbBool rfbInitClient(rfbClient *client, int *argc, char **argv)
Initializes the client.
GotFrameBufferUpdateProc GotFrameBufferUpdate
MallocFrameBufferProc MallocFrameBuffer
int write_video_frame(AVFormatContext *oc, VideoOutputStream *ost, int64_t pts)
VideoOutputStream video_st
void signal_handler(int signal)
int main(int argc, char **argv)
AVFrame * alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
struct timespec start_time cur_time
void movie_close(AVFormatContext **ocp, VideoOutputStream *video_st)
int open_video(AVFormatContext *oc, VideoOutputStream *ost)
AVFormatContext * movie_open(char *filename, VideoOutputStream *video_st, int br, int fr, int w, int h)
int64_t time_to_pts(int framerate, struct timespec *start_time, struct timespec *cur_time)
int write_final_video_frame(AVFormatContext *oc, VideoOutputStream *ost)
int add_video_stream(VideoOutputStream *ost, AVFormatContext *oc, enum AVCodecID codec_id, int64_t br, int sr, int w, int h)
void vnc_update(rfbClient *client, int x, int y, int w, int h)
rfbBool vnc_malloc_fb(rfbClient *client)
void close_video_stream(VideoOutputStream *ost)