[MPlayer-users] Re: Stills and sound from DSC MPEGs

Johan Vromans jvromans at squirrel.nl
Fri Jul 9 19:10:57 CEST 2004


Johan Vromans <jvromans at squirrel.nl> writes:

> 1. My digital camera (Sony DSC V1) can produce short MPEG movies. For
>    cataloging, I'd like to extract a still image from the movie, for
>    example, the first image. I'm sure mplayer/mencoder can do this,
>    but I haven't been able to find out how.

Since I got no answer, I wrote a little tool for this purpose. It is
based on an example from libmpeg2 (http://libmpeg2.sourceforge.net)
and uses the libmpeg2 libraries.

Happy hacking,
-- Johan

/* Quick & Dirty program to fetch the first image from an MPEG file.
 *
 * Requires libmpeg2 (http:/libmpeg2.sourceforge.net).
 */

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>

#include "mpeg2.h"
#include "mpeg2convert.h"

#define BUFFER_SIZE 4096

FILE * ppmfile;

static void save_ppm(int width, int height, uint8_t * buf, int num) {
  fprintf(ppmfile, "P6\n%d %d\n255\n", width, height);
  fwrite(buf, 3 * width, height, ppmfile);
  fclose(ppmfile);
}

static struct fbuf_s {
  uint8_t * rgb[3];
  int used;
} fbuf[3];

static struct fbuf_s * get_fbuf(void) {
  int i;

  for (i = 0; i < 3; i++)
    if (!fbuf[i].used) {
      fbuf[i].used = 1;
      return fbuf + i;
    }
  fprintf(stderr, "Could not find a free fbuf.\n");
  exit(1);
}

static void first_frame_from_mpeg(FILE * mpgfile) {
  uint8_t buffer[BUFFER_SIZE];
  mpeg2dec_t * decoder;
  const mpeg2_info_t * info;
  mpeg2_state_t state;
  size_t size;
  int framenum = 0;
  int pixels;
  int i;
  struct fbuf_s * current_fbuf;

  decoder = mpeg2_init();
  if (decoder == NULL) {
    fprintf(stderr, "Could not allocate a decoder object.\n");
    exit(1);
  }
  info = mpeg2_info(decoder);

  size = (size_t)-1;
  do {
    state = mpeg2_parse(decoder);
    switch(state) {
    case STATE_BUFFER:
      size = fread(buffer, 1, BUFFER_SIZE, mpgfile);
      mpeg2_buffer(decoder, buffer, buffer + size);
      break;
    case STATE_SEQUENCE:
      mpeg2_convert(decoder, mpeg2convert_rgb24, NULL);
      mpeg2_custom_fbuf(decoder, 1);
      pixels = info->sequence->width * info->sequence->height;
      for (i = 0; i < 3; i++) {
	fbuf[i].rgb[0] = (uint8_t *) malloc(3 * pixels);
	fbuf[i].rgb[1] = fbuf[i].rgb[2] = NULL;
	if (!fbuf[i].rgb[0]) {
	  fprintf(stderr, "Could not allocate an output buffer.\n");
	  exit(1);
	}
	fbuf[i].used = 0;
      }
      for (i = 0; i < 2; i++) {
	current_fbuf = get_fbuf();
	mpeg2_set_buf(decoder, current_fbuf->rgb, current_fbuf);
      }
      break;
    case STATE_PICTURE:
      current_fbuf = get_fbuf();
      mpeg2_set_buf(decoder, current_fbuf->rgb, current_fbuf);
      break;
    case STATE_SLICE:
    case STATE_END:
    case STATE_INVALID_END:
      if (info->display_fbuf) {
	save_ppm(info->sequence->width, info->sequence->height,
		  info->display_fbuf->buf[0], framenum++);
	size = 0;		/* terminate */
      }
      if (info->discard_fbuf)
	((struct fbuf_s *)info->discard_fbuf->id)->used = 0;
      if (state != STATE_SLICE)
	for (i = 0; i < 3; i++)
	  free(fbuf[i].rgb[0]);
      break;
    default:
      break;
    }
  } while(size);
  
  mpeg2_close(decoder);
}

int main(int argc, char ** argv) {
  FILE * mpgfile;

  if (argc > 1) {
    mpgfile = fopen(argv[1], "rb");
    if (!mpgfile) {
      fprintf(stderr, "Could not open file \"%s\" (errno = %d)\n",
	       argv[1], errno);
      exit(1);
    }
    if (argc > 2) {
      ppmfile = fopen(argv[2], "wb");
      if (!ppmfile) {
	fprintf(stderr, "Could not create file \"%s\" (errno = %d)\n",
		 argv[2], errno);
	exit(1);
      }
    }
  }
  else
    mpgfile = stdin;

  if (ppmfile == NULL) {
    ppmfile = fopen("out.ppm", "wb");
    if (!ppmfile) {
      fprintf(stderr, "Could not create file \"out.ppm\" (errno = %d)\n",
	       errno);
      exit(1);
    }
  }

  first_frame_from_mpeg(mpgfile);

  return 0;
}




More information about the MPlayer-users mailing list