+++ /dev/null
-/*
- * Simple movie writer for vnc; based on Libavformat API example from FFMPEG
- *
- * Copyright (c) 2003 Fabrice Bellard, 2004 Johannes E. Schindelin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <math.h>
-
-#ifndef M_PI
-#define M_PI 3.1415926535897931
-#endif
-
-#include "avformat.h"
-#include <rfb/rfbclient.h>
-
-#define STREAM_FRAME_RATE 25 /* 25 images/s */
-
-/**************************************************************/
-/* video output */
-
-AVFrame *picture, *tmp_picture;
-uint8_t *video_outbuf;
-int frame_count, video_outbuf_size;
-
-/* add a video output stream */
-AVStream *add_video_stream(AVFormatContext *oc, int codec_id, int w, int h)
-{
- AVCodecContext *c;
- AVStream *st;
-
- st = av_new_stream(oc, 0);
- if (!st) {
- fprintf(stderr, "Could not alloc stream\n");
- exit(1);
- }
-
-#if LIBAVFORMAT_BUILD<4629
- c = &st->codec;
-#else
- c = st->codec;
-#endif
- c->codec_id = codec_id;
- c->codec_type = CODEC_TYPE_VIDEO;
-
- /* put sample parameters */
- c->bit_rate = 800000;
- /* resolution must be a multiple of two */
- c->width = w;
- c->height = h;
- /* frames per second */
-#if LIBAVCODEC_BUILD<4754
- c->frame_rate = STREAM_FRAME_RATE;
- c->frame_rate_base = 1;
-#else
- c->time_base.den = STREAM_FRAME_RATE;
- c->time_base.num = 1;
- c->pix_fmt = PIX_FMT_YUV420P;
-#endif
- c->gop_size = 12; /* emit one intra frame every twelve frames at most */
- if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
- /* just for testing, we also add B frames */
- c->max_b_frames = 2;
- }
- if (c->codec_id == CODEC_ID_MPEG1VIDEO){
- /* needed to avoid using macroblocks in which some coeffs overflow
- this doesnt happen with normal video, it just happens here as the
- motion of the chroma plane doesnt match the luma plane */
- c->mb_decision=2;
- }
- /* some formats want stream headers to be seperate */
- if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- return st;
-}
-
-AVFrame *alloc_picture(int pix_fmt, int width, int height)
-{
- AVFrame *picture;
- uint8_t *picture_buf;
- int size;
-
- picture = avcodec_alloc_frame();
- if (!picture)
- return NULL;
- size = avpicture_get_size(pix_fmt, width, height);
- picture_buf = malloc(size);
- if (!picture_buf) {
- av_free(picture);
- return NULL;
- }
- avpicture_fill((AVPicture *)picture, picture_buf,
- pix_fmt, width, height);
- return picture;
-}
-
-void open_video(AVFormatContext *oc, AVStream *st)
-{
- AVCodec *codec;
- AVCodecContext *c;
-
-#if LIBAVFORMAT_BUILD<4629
- c = &st->codec;
-#else
- c = st->codec;
-#endif
-
- /* find the video encoder */
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- /* open the codec */
- if (avcodec_open(c, codec) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- video_outbuf = NULL;
- if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
- /* allocate output buffer */
- /* XXX: API change will be done */
- video_outbuf_size = 200000;
- video_outbuf = malloc(video_outbuf_size);
- }
-
- /* allocate the encoded raw picture */
- picture = alloc_picture(c->pix_fmt, c->width, c->height);
- if (!picture) {
- fprintf(stderr, "Could not allocate picture\n");
- exit(1);
- }
-
- /* if the output format is not RGB565, then a temporary RGB565
- picture is needed too. It is then converted to the required
- output format */
- tmp_picture = NULL;
- if (c->pix_fmt != PIX_FMT_RGB565) {
- tmp_picture = alloc_picture(PIX_FMT_RGB565, c->width, c->height);
- if (!tmp_picture) {
- fprintf(stderr, "Could not allocate temporary picture\n");
- exit(1);
- }
- }
-}
-
-void write_video_frame(AVFormatContext *oc, AVStream *st)
-{
- int out_size, ret;
- AVCodecContext *c;
- AVFrame *picture_ptr;
-
-#if LIBAVFORMAT_BUILD<4629
- c = &st->codec;
-#else
- c = st->codec;
-#endif
-
- if (c->pix_fmt != PIX_FMT_RGB565) {
- /* as we only generate a RGB565 picture, we must convert it
- to the codec pixel format if needed */
- img_convert((AVPicture *)picture, c->pix_fmt,
- (AVPicture *)tmp_picture, PIX_FMT_RGB565,
- c->width, c->height);
- }
- picture_ptr = picture;
-
-
- if (oc->oformat->flags & AVFMT_RAWPICTURE) {
- /* raw video case. The API will change slightly in the near
- futur for that */
- AVPacket pkt;
- av_init_packet(&pkt);
-
- pkt.flags |= PKT_FLAG_KEY;
- pkt.stream_index= st->index;
- pkt.data= (uint8_t *)picture_ptr;
- pkt.size= sizeof(AVPicture);
-
- ret = av_write_frame(oc, &pkt);
- } else {
- /* encode the image */
- out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture_ptr);
- /* if zero size, it means the image was buffered */
- if (out_size != 0) {
- AVPacket pkt;
- av_init_packet(&pkt);
-
- pkt.pts= c->coded_frame->pts;
- if(c->coded_frame->key_frame)
- pkt.flags |= PKT_FLAG_KEY;
- pkt.stream_index= st->index;
- pkt.data= video_outbuf;
- pkt.size= out_size;
-
- /* write the compressed frame in the media file */
- ret = av_write_frame(oc, &pkt);
- } else {
- ret = 0;
- }
- }
- if (ret != 0) {
- fprintf(stderr, "Error while writing video frame\n");
- exit(1);
- }
- frame_count++;
-}
-
-void close_video(AVFormatContext *oc, AVStream *st)
-{
- avcodec_close(st->codec);
- av_free(picture->data[0]);
- av_free(picture);
- if (tmp_picture) {
- av_free(tmp_picture->data[0]);
- av_free(tmp_picture);
- }
- av_free(video_outbuf);
-}
-
-static const char *filename;
-static AVOutputFormat *fmt;
-static AVFormatContext *oc;
-static AVStream *video_st;
-static double video_pts;
-
-static int movie_open(int w, int h) {
- if (fmt->video_codec != CODEC_ID_NONE) {
- video_st = add_video_stream(oc, fmt->video_codec, w, h);
- } else
- return 1;
-
- /* set the output parameters (must be done even if no
- parameters). */
- if (av_set_parameters(oc, NULL) < 0) {
- fprintf(stderr, "Invalid output format parameters\n");
- return 2;
- }
-
- dump_format(oc, 0, filename, 1);
-
- /* now that all the parameters are set, we can open the audio and
- video codecs and allocate the necessary encode buffers */
- if (video_st)
- open_video(oc, video_st);
-
- /* open the output file, if needed */
- if (!(fmt->flags & AVFMT_NOFILE)) {
- if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
- fprintf(stderr, "Could not open '%s'\n", filename);
- return 3;
- }
- }
-
- /* write the stream header, if any */
- av_write_header(oc);
-
- return 0;
-}
-
-static int movie_close() {
- int i;
-
- /* close each codec */
- close_video(oc, video_st);
-
- /* write the trailer, if any */
- av_write_trailer(oc);
-
- /* free the streams */
- for(i = 0; i < oc->nb_streams; i++) {
- av_freep(&oc->streams[i]);
- }
-
- if (!(fmt->flags & AVFMT_NOFILE)) {
- /* close the output file */
- url_fclose(&oc->pb);
- }
-
- /* free the stream */
- av_free(oc);
-
-}
-
-static rfbBool quit=FALSE;
-static void signal_handler(int signal) {
- fprintf(stderr,"Cleaning up.\n");
- quit=TRUE;
-}
-
-/**************************************************************/
-/* VNC callback functions */
-static rfbBool resize(rfbClient* client) {
- static rfbBool first=TRUE;
- if(!first) {
- movie_close();
- perror("I don't know yet how to change resolutions!\n");
- }
- movie_open(client->width, client->height);
- signal(SIGINT,signal_handler);
- if(tmp_picture)
- client->frameBuffer=tmp_picture->data[0];
- else
- client->frameBuffer=picture->data[0];
- return TRUE;
-}
-
-static void update(rfbClient* client,int x,int y,int w,int h) {
-}
-
-/**************************************************************/
-/* media file output */
-
-int main(int argc, char **argv)
-{
- time_t stop=0;
- rfbClient* client;
- int i,j;
-
- /* get a vnc client structure (don't connect yet). */
- client = rfbGetClient(5,3,2);
- client->format.redShift=11; client->format.redMax=31;
- client->format.greenShift=5; client->format.greenMax=63;
- client->format.blueShift=0; client->format.blueMax=31;
-
- /* initialize libavcodec, and register all codecs and formats */
- av_register_all();
-
- if(!strncmp(argv[argc-1],":",1) ||
- !strncmp(argv[argc-1],"127.0.0.1",9) ||
- !strncmp(argv[argc-1],"localhost",9))
- client->appData.encodingsString="raw";
-
- filename=0;
- for(i=1;i<argc;i++) {
- j=i;
- if(argc>i+1 && !strcmp("-o",argv[i])) {
- filename=argv[2];
- j+=2;
- } else if(argc>i+1 && !strcmp("-t",argv[i])) {
- stop=time(0)+atoi(argv[i+1]);
- j+=2;
- }
- if(j>i) {
- argc-=j-i;
- memmove(argv+i,argv+j,(argc-i)*sizeof(char*));
- i--;
- }
- }
-
-
- /* auto detect the output format from the name. default is
- mpeg. */
- fmt = filename?guess_format(NULL, filename, NULL):0;
- if (!fmt) {
- printf("Could not deduce output format from file extension: using MPEG.\n");
- fmt = guess_format("mpeg", NULL, NULL);
- }
- if (!fmt) {
- fprintf(stderr, "Could not find suitable output format\n");
- exit(1);
- }
-
- /* allocate the output media context */
- oc = av_alloc_format_context();
- if (!oc) {
- fprintf(stderr, "Memory error\n");
- exit(1);
- }
- oc->oformat = fmt;
- snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
-
- /* add the audio and video streams using the default format codecs
- and initialize the codecs */
- video_st = NULL;
-
- /* open VNC connection */
- client->MallocFrameBuffer=resize;
- client->GotFrameBufferUpdate=update;
- if(!rfbInitClient(client,&argc,argv)) {
- printf("usage: %s [-o output_file] [-t seconds] server:port\n"
- "Shoot a movie from a VNC server.\n", argv[0]);
- exit(1);
- }
- if(client->serverPort==-1)
- client->vncRec->doNotSleep = TRUE; /* vncrec playback */
-
- /* main loop */
-
- while(!quit) {
- int i=WaitForMessage(client,1000000/STREAM_FRAME_RATE);
- if(i<0) {
- movie_close();
- return 0;
- }
- if(i)
- if(!HandleRFBServerMessage(client))
- quit=TRUE;
- else {
- /* compute current audio and video time */
- video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
-
- /* write interleaved audio and video frames */
- write_video_frame(oc, video_st);
- }
- if(stop!=0 && stop<time(0))
- quit=TRUE;
- }
-
- movie_close();
- return 0;
-}