Home My Page Projects Code Snippets Project Openings 3D graphics for Standard ML
Summary Activity SCM

SCM Repository

[sml3d] View of /trunk/sml3d/src/movie/movie-glue_c.in
ViewVC logotype

View of /trunk/sml3d/src/movie/movie-glue_c.in

Parent Directory Parent Directory | Revision Log Revision Log


Revision 985 - (download) (annotate)
Sun Dec 19 00:28:59 2010 UTC (8 years, 11 months ago) by jhr
File size: 4109 byte(s)
  Tweaking code
/* movie-glue.c
 *
 * COPYRIGHT (c) 2010 John Reppy (http://cs.uchicago.edu/~jhr)
 * All rights reserved.
 *
 * Code to capture OpenGL frames as video.  This version works by running mencoder as a
 * subprocess and piping the raw 24-bit frames to it.
 *
 * @configure_input@
 *
 * TODO:
 *	allow choice of codec
 *	allow choice of fps (using something other than 25 results in corruption)
 *	more error checking
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#if defined(__APPLE__) && defined(__MACH__)
#  include <OpenGL/gl.h>
#else
#  include <GL/gl.h>
#endif

#define MENCODER	"@MENCODER@"

typedef struct {
    FILE		*pipe;		//!< UNIX pipe used to send raw frames to mencoder
    unsigned char	*buf;		//!< buffer for extracting frames from OpenGL framebuffer
    int			x, y;		//!< coordinates of the frame's origin
    int			width, height;  //!< dimensions of the frame
} Movie_t;


/*! \brief create an output movie stream.
 *  \param filename output file name
 *  \param x frame origin x coordinate
 *  \param y frame origin y coordinate
 *  \param wid frame width
 *  \param ht frame height
 *  \param fps requested frames per second (currently not used)
 *  \param codecName the name of the codec (currently not used)
 *  \return the new movie stream or 0
 */
Movie_t *SML3D_InitMovie (const char *filename, int x, int y, int wid, int ht, int fps, const char *codecName)
{
    char		cmdBuf[512];
    unsigned char	*buffer = 0;
    FILE		*pipe = NULL;

  /* format the mencoder command line.  The options are as follows:
   *
   *	-rawvideo w=<width>:h=<height>:fps=<fps>:format=RGB24
   *		specifies input is raw video frames of size width x height and 24-bits per
   *		pixel.  The frame rate is specified by fps.
   *
   *	-demuxer rawvideo
   *		forces demuxer to be rawvideo
   *
   *	-ovc lacv
   *		use the libavcodec codecs (these are supposed to be the best quality)
   *
   *	-lavcopts vcodec=mpeg4:vbitrate=1800
   *		use the MPEG-4 codec to encode the output video with a video bitrate of 1800K bits
   */
    int sts = snprintf (cmdBuf, sizeof(cmdBuf),
	"%s - -rawvideo w=%d:h=%d:fps=%d:format=RGB24 -demuxer rawvideo -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=1600 -o %s",
	MENCODER, wid, ht, 25, filename);

    if (sts >= sizeof(cmdBuf)) {
	fprintf (stderr, "SML3D_InitMovie: error formatting mencoder command\n");
	goto error;
    }

    buffer = (unsigned char *) malloc (4*wid*ht*sizeof(unsigned char));
    if (buffer == 0) {
	fprintf (stderr, "SML3D_InitMovie: unable to allocate buffer\n");
	goto error;
    }

    pipe = popen (cmdBuf, "w");
    if (pipe == NULL) {
	fprintf(stderr, "SML3D_InitMovie: unable to start mencoder\n");
	goto error;
    }

    Movie_t *mov = (Movie_t *)malloc(sizeof(Movie_t));
    mov->pipe = pipe;
    mov->buf = buffer;
    mov->x = x;
    mov->y = y;
    mov->width = wid;
    mov->height = ht;

    return mov;

  error:;
    if (pipe != 0) pclose (pipe);
    if (buffer != 0) free (buffer);
    return 0;

}

/*! \brief close the movie stream and release its resources.
 */
void SML3D_FinishMovie (Movie_t *mov)
{
    if (mov->pipe == NULL)
	return;

    pclose (mov->pipe);
    free (mov->buf);
    free (mov);

}

/*! \brief record a frame to the movie stream.
 */
void SML3D_RecordFrame (Movie_t *mov)
{
  // select front buffer as our source for pixel data
    glReadBuffer(GL_FRONT);
    
  // For extra safety, save & restore OpenGL states that are changed
    glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
    
    glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

    glReadPixels (
	mov->x, mov->y, mov->width, mov->height,
	GL_RGB, GL_UNSIGNED_BYTE,
	mov->buf);

    glPopClientAttrib();

  // flip by writing the rows out backwards
    int rowSpan = 3 * mov->width;
    unsigned char *p = mov->buf + (rowSpan * (mov->height-1));
    for (int i = 0;  i < mov->height;  i++) {
	fwrite (p, 1, rowSpan, mov->pipe);
	p -= rowSpan;
    }

}

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0