[Mplayer-cvslog] CVS: main/libmp1e Makefile,NONE,1.1 b_mp1e.c,NONE,1.1 global_data.c,NONE,1.1 libmp1e.h,NONE,1.1 main.h,NONE,1.1 options.h,NONE,1.1 rte.c,NONE,1.1 rtepriv.h,NONE,1.1 site_def.h,NONE,1.1

David Holm mswitch at mplayer.dev.hu
Wed Dec 5 00:53:57 CET 2001


Update of /cvsroot/mplayer/main/libmp1e
In directory mplayer:/var/tmp.root/cvs-serv17446

Added Files:
	Makefile b_mp1e.c global_data.c libmp1e.h main.h options.h 
	rte.c rtepriv.h site_def.h 
Log Message:
This is the first version of libmp1e the ULTRA fast mpeg1 encoder, the api isn't done yet so don't start using it quite yet. I'll let you know when it's done (hopefully tomorrow)



--- NEW FILE ---

include ../config.mak

LIBNAME = libmp1e.a

SRCS = audio/fft.c audio/filter.c audio/mp2.c audio/psycho.c audio/tables.c \
    common/alloc.c common/bstream.c common/fifo.c common/mmx.c common/profile.c common/sync.c common/errstr.c \
    systems/mpeg1.c systems/mpeg2.c systems/rte_output.c systems/systems.c systems/vcd.c \
    video/dct.c video/dct_ref.c video/filter.c video/mblock.c video/motion.c video/mpeg1.c video/tables.c video/vlc.c \
    global_data.c b_mp1e.c rte.c

ASM_SRCS = 

CFLAGS= $(OPTFLAGS) $(INCLUDE) \
    -DHAVE_CONFIG_H -D_GNU_SOURCE -D_REENTRANT -DFLOAT=float -I. -I.. -fPIC

LFLAGS = 

# i386 specific stuff
ifeq ($(TARGET_MMX),yes)
ASM_SRCS += audio/filter_mmx.s \
    common/bstream_mmx.s \
    video/dct_mmx.s video/filter_mmx.s video/motion_mmx.s video/vlc_mmx.s
endif

ifeq ($(TARGET_SSE2),yes)
ASM_SRCS += video/motion_sse2.s
endif

OBJS=$(SRCS:.c=.o)
ASM_OBJS=$(ASM_SRCS:.s=.o)

.SUFFIXES: .c .s .o .lo

# .PHONY: all clean

all:	$(LIBNAME)

.c.o:
	$(CC) -c $(CFLAGS) -o $@ $<

.s.o:
	$(CC) -c $(CFLAGS) -o $@ $<

$(LIBNAME):	$(OBJS) $(ASM_OBJS)
	ar rs $(LIBNAME) $(OBJS) $(ASM_OBJS)

clean:
	rm -f $(ASM_OBJS) $(OBJS) $(LIBNAME)

distclean: clean
	rm -f .depend

dep:	depend

depend:
	$(CC) -MM $(CFLAGS) $(SRCS) $(ASM_SRCS) 1>.depend

ifneq ($(wildcard .depend),)
include .depend
endif

--- NEW FILE ---
/*
 *  Real Time Encoder lib
 *  mp1e backend
 *
 *  Copyright (C) 2000-2001 Iñaki García Etxebarria
 *  Modified 2001 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: b_mp1e.c,v 1.1 2001/12/04 23:53:53 mswitch Exp $ */

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>

#include "options.h"
#include "common/mmx.h"
#include "common/math.h"
#include "video/video.h"
#include "audio/libaudio.h"
#include "audio/mpeg.h"
#include "video/mpeg.h"
#include "systems/systems.h"
#include "common/profile.h"
#include "common/log.h"
#include "common/mmx.h"
#include "common/bstream.h"
#include "common/sync.h"
#include "common/fifo.h"
#include "main.h"

#include "rtepriv.h"

typedef struct {
	rte_context_private	priv;

	multiplexer *mux;

	pthread_t mux_thread; /* mp1e multiplexer thread */
	pthread_t video_thread_id; /* video encoder thread */
	pthread_t audio_thread_id; /* audio encoder thread */

	/* Experimental */

	unsigned int codec_set;
	rte_codec *video_codec;
	rte_codec *audio_codec;

} backend_private;

/* translates the context options to the global mp1e options */
static int rte_fake_options(rte_context * context);
/* prototypes for main initialization (mp1e startup) */
/* These routines are called in this order, they come from mp1e's main.c */
static void rte_audio_startup(void); /* Startup video parameters */
/* init routines */
static void rte_audio_init(rte_context *context, backend_private *priv); /* init audio capture */
static void rte_video_init(rte_context *context, backend_private *priv); /* init video capture */

/*
 * Global options from rte.
 */
static int			verbose=0;
static int			stereo;

/* fixme: This is just to satisfy dependencies for now */
void
packed_preview(unsigned char *buffer, int mb_cols, int mb_rows)
{
}

static void
context_new			(rte_context	*context)
{
	backend_private *priv = (backend_private*)context->private;

	context->format = strdup("mpeg1");

	priv->codec_set = 0;
}

static void
context_destroy			(rte_context	*context)
{
	free(context->format);
}

static int
init_context			(rte_context	*context)
{
	backend_private *priv = (backend_private*)context->private;

	if (!context->format)
	{
		rte_error(context, "format == NULL !!!");
		return 0;
	}
	if (strcmp(context->format, "mpeg1"))
	{
		rte_error(context, "mp1e backend only supports \"mpeg1\""
			" format.");
		return 0;
	}

	if (context->mode == 0)
		return 0;

	if (context->mode & RTE_AUDIO)
	{
		context->audio_bytes = 4096 * sizeof(short);

		switch (context->audio_mode)
		{
		case RTE_AUDIO_MODE_STEREO:
			context->audio_bytes *= 2;
			break;

		default:
			break;
		}
	}

	if (!rte_fake_options(context))
		return 0;

	/* Init the mp1e engine, as main would do */
	if (!(priv->mux = mux_alloc(context)))
	{
		rte_error(context, "Cannot init output");
		return 0;
	}

	rte_audio_startup();

	rte_audio_init(context, priv);
	rte_video_init(context, priv);

	if (!output_init())
	{
		rte_error(context, "Cannot init output");
		mux_free(priv->mux);
		return 0;
	}

	return 1;
}

/* preliminary; fifos must be ready at this point */

static int
post_init_context		(rte_context	*context)
{
	backend_private *priv = (backend_private*)context->private;

	if (modules & MOD_AUDIO) {
		mp1e_mp2_init(priv->audio_codec, MOD_AUDIO, &priv->priv.aud,
			      priv->mux);
	}

	if (modules & MOD_VIDEO) {
		video_init(priv->video_codec, cpu_type, width, height,
			   motion_min, motion_max, /* preliminary */
			   &priv->priv.vid, MOD_VIDEO, priv->mux);
	}

	return 1;
}

static void
uninit_context			(rte_context	*context)
{
	backend_private *priv = (backend_private*)context->private;

	output_end();

	mux_free(priv->mux);
}

static int
start			(rte_context	*context)
{
	backend_private *priv = (backend_private*)context->private;

	if (modules & MOD_VIDEO)
		/* Use video as time base (broadcast and v4l2 assumed) */
		mp1e_sync_init(modules, MOD_VIDEO);
	else if (modules & MOD_SUBTITLES)
		mp1e_sync_init(modules, MOD_SUBTITLES);
	else
		mp1e_sync_init(modules, MOD_AUDIO);
	/* else mp1e_sync_init(modules, 0); use TOD */

	if (modules & MOD_AUDIO) {
		ASSERT("create audio compression thread",
			!pthread_create(&priv->audio_thread_id,	NULL,
					priv->audio_codec->class->mainloop,
					priv->audio_codec));

		printv(2, "Audio compression thread launched\n");
	}

	if (modules & MOD_VIDEO) {
		ASSERT("create video compression thread",
			!pthread_create(&priv->video_thread_id,
					NULL,
					mpeg1_video_ipb, priv->video_codec));
				//	(fifo *) &(context->private->vid)));

		printv(2, "Video compression thread launched\n");
	}

	switch (modules) {
	case MOD_VIDEO:
	case MOD_AUDIO:
		ASSERT("create elementary stream thread",
		       !pthread_create(&priv->mux_thread, NULL,
				       elementary_stream_bypass, priv->mux));
		break;

	default: /* both */
		printv(1, "MPEG-1 Program Stream\n");
		ASSERT("create mpeg1 system mux",
		       !pthread_create(&priv->mux_thread, NULL,
				       mpeg1_system_mux, priv->mux));
		break;
	}

	mp1e_sync_start(0.0);

	return 1;
}

static void
stop			(rte_context	*context)
{
	backend_private *priv = (backend_private*)context->private;

	/* Tell the mp1e threads to shut down */
	mp1e_sync_stop(0.0); // now

	if (context->mode & RTE_VIDEO) {
		printv(2, "joining video\n");
		pthread_join(priv->video_thread_id, NULL);
		printv(2, "video joined\n");
	}

	if (context->mode & RTE_AUDIO) {
		printv(2, "joining audio\n");
		pthread_join(priv->audio_thread_id, NULL);
		printv(2, "audio joined\n");
	}

	/* Join the mux thread */
	printv(2, "joining mux\n");
	pthread_join(priv->mux_thread, NULL);
	printv(2, "mux joined\n");
}

static char*
query_format		(rte_context	*context,
			 int n,
			 enum rte_mux_mode	*mux_mode)
{
	if (n)
		return 0;

	if (mux_mode)
		*mux_mode = RTE_AUDIO_AND_VIDEO;

	return "mpeg1";
}

/*
 *  XXX this should be context / codec
 *  (ie. stream status and mux status)
 */
static void
status			(rte_context	*context,
			 struct rte_status_info	*status)
{
	backend_private *priv = (backend_private *) context->private;

	status->bytes_out = priv->priv.bytes_out;

	if (context->mode == RTE_AUDIO) {
		rte_codec *codec = priv->audio_codec;

		pthread_mutex_lock(&codec->mutex);
		status->processed_frames = codec->frame_output_count;
		pthread_mutex_unlock(&codec->mutex);

		status->dropped_frames = 0;
	} else {
		status->processed_frames = video_frame_count;
		status->dropped_frames = video_frames_dropped;
	}
}

static int rte_fake_options(rte_context * context)
{
//	backend_private *priv = (backend_private*)context->private;
	int pitch;

	ASSERT("guiroppaaaaa!\n", context != NULL);

	gop_sequence = context->gop_sequence;

	modules = context->mode;

	if (context->width < 1 || context->width > MAX_WIDTH
	    || context->height < 1 || context->height > MAX_HEIGHT) {
		rte_error(context, "Image size %dx%d out of bounds",
			  context->width, context->height);
		return 0;
	}

	grab_width = context->width;
	grab_height = context->height;

	if ((context->video_rate == RTE_RATE_NORATE) ||
	    (context->video_rate > RTE_RATE_8)) {
		rte_error(context, "Invalid frame rate: %d",
			  context->video_rate);
		context->video_rate = RTE_RATE_3; /* default to PAL */
	}

	switch (context->video_format) {
	case RTE_YUYV_PROGRESSIVE:
	case RTE_YUYV_PROGRESSIVE_TEMPORAL:
//		vseg.frame_rate_code += 3;
	case RTE_YUYV_VERTICAL_DECIMATION:
	case RTE_YUYV_TEMPORAL_INTERPOLATION:
	case RTE_YUYV_VERTICAL_INTERPOLATION:
	case RTE_YUYV_EXP:
	case RTE_YUYV_EXP_VERTICAL_DECIMATION:
	case RTE_YUYV_EXP2:
// XXX
		pitch = grab_width*2;
		filter_mode =
			(context->video_format-RTE_YUYV_VERTICAL_DECIMATION) + 
			CM_YUYV_VERTICAL_DECIMATION;
		rte_error(context, "Video format %d temporarily out of order",
			  context->video_rate);
		return 0;
		break;
	case RTE_YUYV:
		filter_mode = CM_YUYV;
		pitch = grab_width * 2;
		break;
	case RTE_YUV420:
		filter_mode = CM_YUV;
		pitch = grab_width;
		break;
	case RTE_YVU420:
		filter_mode = CM_YVU;
		pitch = grab_width;
		break;
	default:
		rte_error(context, "unknown pixformat %d", context->video_format);
		return 0;
	}

	width = context->width;
	height = context->height;

	filter_init(pitch);

	if ((width != grab_width) || (height != grab_height))
		rte_error(NULL, "requested %dx%d, got %dx%d",
			  grab_width, grab_height, width, height);

	video_bit_rate = context->output_video_bits;
	audio_bit_rate = context->output_audio_bits;
	audio_bit_rate_stereo = audio_bit_rate * 2;

	sampling_rate = context->audio_rate;

	switch (context->audio_mode) {
	case RTE_AUDIO_MODE_MONO:
		audio_mode = AUDIO_MODE_MONO;
		break;
	case RTE_AUDIO_MODE_STEREO:
		audio_mode = AUDIO_MODE_STEREO;
		break;
	default:
		rte_error(context, "unknown audio mode %d",
			  context->audio_mode);
		return 0;
	}

	motion_min = context->motion_min;
	motion_max = context->motion_max;

	return 1;
}

/* Startup audio parameters */
static void rte_audio_startup(void)
{
	if (modules & MOD_AUDIO) {
		int psy_level = audio_mode / 10;
		
		audio_mode %= 10;
		
		stereo = (audio_mode != AUDIO_MODE_MONO);
		audio_parameters(&sampling_rate, &audio_bit_rate);
		
		if ((audio_bit_rate >> stereo) < 80000 || psy_level >= 1) {
			psycho_loops = MAX(psycho_loops, 1);
			
			if (sampling_rate < 32000 || psy_level >= 2)
				psycho_loops = 2;
			
			psycho_loops = MAX(psycho_loops, 2);
		}
	}
}

/* FIXME: Subtitles support */

static void rte_audio_init(rte_context *context, backend_private *priv)
/* init audio capture */
{
	if (modules & MOD_AUDIO) {
		if (modules & MOD_VIDEO)
			audio_num_frames = llroundn(((double) video_num_frames /
						     frame_rate_value[context->video_rate])
						    / (1152.0 / sampling_rate));
		/* preliminary */

		if (!priv->audio_codec) {
			rte_stream_parameters rsp;

			if (sampling_rate < 32000)
				priv->audio_codec = mp1e_mpeg2_layer2_codec.new();
			else
				priv->audio_codec = mp1e_mpeg1_layer2_codec.new();

			assert(priv->audio_codec);

			rte_helper_set_option_va(priv->audio_codec, "sampling_rate", sampling_rate);
			rte_helper_set_option_va(priv->audio_codec, "bit_rate", audio_bit_rate);
			rte_helper_set_option_va(priv->audio_codec, "audio_mode",
						 (int) "\1\3\2\0"[audio_mode]);
			rte_helper_set_option_va(priv->audio_codec, "psycho", (int) psycho_loops);

			memset(&rsp, 0, sizeof(rsp));
			priv->audio_codec->class->parameters(priv->audio_codec, &rsp);
		}
	}
}

static void rte_video_init(rte_context *context, backend_private *priv)
/* init video capture */
{
	if (modules & MOD_VIDEO) {
		video_coding_size(width, height);

		if (frame_rate > frame_rate_value[context->video_rate])
			frame_rate = frame_rate_value[context->video_rate];

		/* preliminary */

		if (!priv->video_codec) {
			priv->video_codec = mp1e_mpeg1_video_codec.new();

			assert(priv->video_codec);

			rte_helper_set_option_va(priv->video_codec, "bit_rate", video_bit_rate);
			/* vseg.frame_rate_code above
			   rte_helper_set_option_va(priv->video_codec, "coded_frame_rate", ?); */
			rte_helper_set_option_va(priv->video_codec, "virtual_frame_rate",
						 frame_rate);
			rte_helper_set_option_va(priv->video_codec, "skip_method", 0);
			rte_helper_set_option_va(priv->video_codec, "gop_sequence", gop_sequence);
//			rte_helper_set_option_va(priv->video_codec, "motion_compensation",
//						 motion_min > 0 && motion_max > 0);
			rte_helper_set_option_va(priv->video_codec, "monochrome", !!luma_only);
			rte_helper_set_option_va(priv->video_codec, "anno", anno);
		}
	}
}

/* Experimental */

static rte_codec_class
mp1e_vbi_codec = {
	.public = {
		.stream_type = RTE_STREAM_SLICED_VBI,
		.keyword = "dvb_vbi",
		.label = "DVB VBI Stream (Subtitles)",
		.tooltip = "Note the recording of Teletext and Closed Caption "
			"services in *MPEG-1* Program Streams is not covered "
			"by the DVB standard. Unaware players should ignore "
			"VBI data.",
	},
};

static rte_codec_class *
codec_table[] = {
	&mp1e_mpeg1_video_codec,
	&mp1e_mpeg1_layer2_codec,
	&mp1e_mpeg2_layer2_codec,
	&mp1e_vbi_codec,
};

#define NUM_CODECS (sizeof(codec_table) / sizeof(codec_table[0]))

static rte_codec_info *
codec_enum(rte_context *context, int index)
{
	if (index < 0 || index >= NUM_CODECS)
		return NULL;

	return &codec_table[index]->public;
}

static rte_codec *
codec_get(rte_context *context, rte_stream_type stream_type, int stream_index)
{
	backend_private *priv = (backend_private *) context->private;
	rte_codec_class *info;
	rte_codec *codec;

	if (stream_index != 0)
		goto bad;

	switch (stream_type) {
	case RTE_STREAM_VIDEO:
		/* find in stream table */
		if ((codec = priv->video_codec))
			info = priv->video_codec->class;
		else
			goto bad;
		break;

	case RTE_STREAM_AUDIO:
		/* find in stream table */
		if ((codec = priv->audio_codec))
			info = priv->audio_codec->class;
		else
			goto bad;
		break;

	case RTE_STREAM_SLICED_VBI:
		codec = (rte_codec *) 4;
		if (priv->codec_set & 0x08)
			info = &mp1e_vbi_codec;
		else
			goto bad;
		break;

	default:
	bad:
		return NULL;
	}

	return codec;
}

static rte_codec *
codec_set(rte_context *context, rte_stream_type stream_type,
	  int stream_index, char *codec_keyword)
{
	backend_private *priv = (backend_private *) context->private;
	rte_codec *codec = NULL;
	int i;

	if (stream_index != 0)
		return NULL; /* TODO */

	for (i = 0; i < NUM_CODECS; i++)
		if (codec_table[i]->public.stream_type == stream_type
		    && (!codec_keyword
			|| 0 == strcmp(codec_table[i]->public.keyword,
				       codec_keyword)))
			break;

	if (i >= NUM_CODECS)
		return NULL;

	switch (stream_type) {
	case RTE_STREAM_VIDEO:
		if (priv->video_codec) {
			priv->video_codec->class->delete(priv->video_codec);
			priv->video_codec = NULL;
			/* preliminary */ priv->codec_set &= ~(1 << 0);
		}

		if (codec_keyword) {
			codec = codec_table[i]->new();

			if ((priv->video_codec = codec)) {
				codec->context = context;
				priv->codec_set |= 1 << 0;
			}
		}

		break;

	case RTE_STREAM_AUDIO:
		if (priv->audio_codec) {
			priv->audio_codec->class->delete(priv->audio_codec);
			priv->audio_codec = NULL;
			/* preliminary */ priv->codec_set &= ~(1 << 1);
		}

		if (codec_keyword) {
			codec = codec_table[i]->new();

			if ((priv->audio_codec = codec)) {
				codec->context = context;
				priv->codec_set |= 1 << 1;
			}
		}

		break;

	case RTE_STREAM_SLICED_VBI:
	default:
		return NULL; /* todo */
	}

	switch (priv->codec_set) {
	case 0:
		context->mode = 0;
		break;
	case 1:
		context->mode = RTE_VIDEO;
		break;
	case 2:
	case 4:
		context->mode = RTE_AUDIO;
		break;
	case 3:
	case 5:
		context->mode = RTE_AUDIO_AND_VIDEO;
		break;
	default:
		assert(!"reached");
	}

	return codec;
}

static rte_option_info *
option_enum(rte_codec *codec, int index)
{
//	rte_context *context = codec->context;

	/* Preliminary */

	switch ((int) codec) {
	case 4: /* VBI */
		return NULL; /* TODO */

	default:
		return codec->class->option_enum(codec, index);
	}
}

#include <stdarg.h>

static int
option_get(rte_codec *codec, char *keyword, rte_option_value *v)
{
//	rte_context *context = codec->context;

	/* Preliminary */

	switch ((int) codec) {
	case 4: /* VBI */
		return 0; /* TODO */

	default:
		return codec->class->option_get(codec, keyword, v);
	}
}

static int
option_set(rte_codec *codec, char *keyword, va_list args)
{
//	rte_context *context = codec->context;

	/* Preliminary */

	switch ((int) codec) {
	case 4: /* VBI */
		return 0; /* TODO */

	default:
		return codec->class->option_set(codec, keyword, args);
	}
}

static char *
option_print(rte_codec *codec, char *keyword, va_list args)
{
//	rte_context *context = codec->context;

	/* Preliminary */

	switch ((int) codec) {
	case 4: /* VBI */
		return 0; /* TODO */

	default:
		return codec->class->option_print(codec, keyword, args);
	}
}

static int
parameters(rte_codec *codec, rte_stream_parameters *rsp)
{
	rte_context *context = codec->context;
	backend_private *priv = (backend_private *) context->private;
//	rte_option_value val;

	/* Preliminary */

	if (codec != priv->audio_codec)
		return 0;

	return codec->class->parameters(codec, rsp);
}

#define N_(x) x

static rte_context_class
mp1e_mpeg1_ps_context = {
	.public = {
		.keyword	= "mp1e-mpeg1-ps",
		.backend	= "mp1e 1.9.2",
		.label		= N_("MPEG-1 Program Stream"),

		.mime_type	= "video/x-mpeg",
		.extension	= "mpg,mpe,mpeg",

		.elementary	= { 0, 1, 1 }, /* to be { 0, 16, 32 }, */
	},
};

static rte_context_class
mp1e_mpeg1_vcd_context = {
	.public = {
		.keyword	= "mp1e-mpeg1-vcd",
		.backend	= "mp1e 1.9.2",
		.label		= N_("MPEG-1 VCD Program Stream"),

		.mime_type	= "video/x-mpeg",
		.extension	= "mpg,mpe,mpeg",

		.elementary	= { 0, 1, 1 }, /* to be { 0, 16, 32 }, */
	},
};

static rte_context_class
mp1e_mpeg1_video_context = {
	.public = {
		.keyword	= "mp1e-mpeg-video",
		.backend	= "mp1e 1.9.2",
		.label		= N_("MPEG Video Elementary Stream"),

		.mime_type	= "video/mpeg",
		.extension	= "mpg,mpe,mpeg",

		.elementary	= { 0, 1, 0 },
	},
};

static rte_context_class
mp1e_mpeg1_audio_context = {
	.public = {
		.keyword	= "mp1e-mpeg-audio",
		.backend	= "mp1e 1.9.2",
		.label		= N_("MPEG Audio Elementary Stream"),

		.mime_type	= "audio/mpeg",
		.extension	= "mp2,mpga", /* note */

		.elementary	= { 0, 0, 1 },
	},
};

static rte_context_class *
context_table[] = {
	&mp1e_mpeg1_ps_context,
};

#define NUM_CONTEXTS (sizeof(context_table) / sizeof(context_table[0]))

static rte_context_info *
context_enum(int index)
{
	if (index < 0 || index >= NUM_CONTEXTS)
		return NULL;

	return &context_table[index]->public;
}

static rte_context *
context_new2(char *keyword)
{
	rte_context *context;

//	if (strcmp(keyword, "mp1e-mpeg1-ps") != 0)
//		return NULL;

	if (!(context = calloc(1, sizeof(rte_context)))) {
//XXX		rte_error(NULL, "malloc(): [%d] %s", errno, strerror(errno));
		return NULL;
	}

	if (!(context->private = calloc(1, sizeof(backend_private)))) {
//XXX		rte_error(NULL, "malloc(): [%d] %s", errno, strerror(errno));
		free(context);
		return NULL;
	}

	context->private->class = &mp1e_mpeg1_ps_context;

	/* Legacy */

	context->format = strdup("mpeg1");

	((backend_private *) context->private)->codec_set = 0;

	return context;
}

static void
context_delete(rte_context *context)
{
	free(context->format);
	free(context->private);
	free(context);
}

static int
init_backend			(void)
{
	extern const rte_backend_info b_mp1e_info;
	int i;

	cpu_type = cpu_detection();

	if (cpu_type == CPU_UNKNOWN)
	{
		rte_error(NULL, "mp1e backend requires MMX");
		return 0;
	}

	for (i = 0; i < NUM_CONTEXTS; i++) {
		context_table[i]->codec_enum = b_mp1e_info.codec_enum;
		context_table[i]->codec_get = b_mp1e_info.codec_get;
		context_table[i]->codec_set = b_mp1e_info.codec_set;
		context_table[i]->option_enum = b_mp1e_info.option_enum;
		context_table[i]->option_get = b_mp1e_info.option_get;
		context_table[i]->option_set = b_mp1e_info.option_set;
		context_table[i]->option_print = b_mp1e_info.option_print;
		context_table[i]->parameters = b_mp1e_info.parameters;
	}

	mp1e_mp2_module_init(0);

	return 1;
}

const
rte_backend_info b_mp1e_info =
{
	"mp1e",
	sizeof(backend_private),
	init_backend,
	context_new,	/* obsolete */
	context_destroy, /* obsolete */
	init_context,
	post_init_context,
	uninit_context,
	start,
	stop,
	query_format,
	status,

	.context_enum	= context_enum,
	.context_new2	= context_new2,
	.context_delete	= context_delete,

	.codec_enum	= codec_enum,
	.codec_get	= codec_get,
	.codec_set	= codec_set,

	.option_enum	= option_enum,
	.option_get	= option_get,
	.option_set	= option_set,
	.option_print	= option_print,

	.parameters	= parameters,
};

--- NEW FILE ---
/*
 *  MPEG-1 Real Time Encoder
 *
 *  Copyright (C) 2000 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: global_data.c,v 1.1 2001/12/04 23:53:53 mswitch Exp $ */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <ctype.h>
#include <limits.h>
#include <unistd.h>
#include <sys/time.h>
#include <asm/types.h>
#include <linux/soundcard.h>
#include "common/types.h"
#include "common/log.h"
#include "common/fifo.h"
#include "video/video.h"
#include "audio/mpeg.h"
#include "options.h"

/*
 *  Factory defaults, use system wide configuration file to customize
 */
int			test_mode		= 0;

int			modules			= 3;			// 1 = Video, 2 = Audio, 4 = VBI
int			mux_syn			= 2;			// 0 = null, elementary, MPEG-1, MPEG-2 PS 

char *			cap_dev			= "/dev/video";

#if defined(HAVE_LIBASOUND)
/* alsa 0.5: card #0, device #0; 0.9: "default" */
char *			pcm_dev			= "alsa";
#elif defined(HAVE_OSS)
char *			pcm_dev			= "/dev/dsp";
#elif defined(USE_ESD)
char *			pcm_dev			= "esd";
#else
char *			pcm_dev			= "";
#endif

char *			mix_dev			= "/dev/mixer";
char *			vbi_dev			= "/dev/vbi";

int			width			= 352;
int			height			= 288;
int			grab_width		= 352;
int			grab_height		= 288;
// defaults to width/height if given
int			video_bit_rate		= 2300000;
long long		video_num_frames	= INT_MAX; /* XXX rounding */
char *			gop_sequence		= "IBBPBBPBBPBB";
// int			frames_per_seqhdr	= 50;
int			filter_mode		= CM_YUYV_VERTICAL_DECIMATION;
double			frame_rate		= 1000.0;
int			preview			= 0;			// 0 = none, XvImage/GTK, progressive
char *			anno			= NULL;
int			luma_only		= 0;			// boolean
int			motion_min		= 0;
int			motion_max		= 0;
int			skip_method		= 0;			// compatible

int			audio_bit_rate		= 80000;
int			audio_bit_rate_stereo	= 160000;
long long		audio_num_frames	= INT_MAX;
int			sampling_rate		= 44100;
int			mix_line		= SOUND_MIXER_LINE;	// soundcard.h
int			mix_volume		= 80;			// 0 <= n <= 100
int			audio_mode		= AUDIO_MODE_MONO;
int			psycho_loops		= 0;			// 0 = static psy, low, hi quality
int			mute			= 0;			// bttv specific, boolean

char *			subtitle_pages		= NULL;

#if LARGE_MEM // XXX make this an option
int			cap_buffers		= 4*12;			// capture -> video compression
int			vid_buffers		= 4*8;			// video compression -> mux
int			aud_buffers		= 4*32;			// audio compression -> mux
#else
int			cap_buffers		= 12;			// capture -> video compression
int			vid_buffers		= 8;			// video compression -> mux
int			aud_buffers		= 32;			// audio compression -> mux
#endif

int			cpu_type		= 0;			// detect

--- NEW FILE ---
/*
 *  MPEG-1 Real Time Encoder lib wrapper api
 *
 *  Copyright (C) 2000-2001 Iñaki García Etxebarria
 *  Modified 2001 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * Function prototypes for RTE
 */

#ifndef MP1ERTE_H
#define MP1ERTE_H

/*
 * What are we going to encode, audio only, video only or both
 * FIXME: subtitles?
 * to be removed, replacement codec_get|set
 */
enum rte_mux_mode {
	RTE_VIDEO = 1,
	RTE_AUDIO = 2,
	RTE_AUDIO_AND_VIDEO = 3 /* AUDIO | VIDEO */
};

/*
 * Which interface rte will use for fetching data.
 */
enum rte_interface {
	RTE_NO_INTERFACE = 0,
	RTE_PUSH = 1, /* the push_* family of functions will be used */
	RTE_CALLBACKS = 2 /* callbacks will be provided by the app */
};

/*
  Supported pixformats. This is the pixformat the pushed video frames
  will be pushed in, the output (encoded) format is the one specified
  by the MPEG standard (YCbCr)
  The YUV formats are in the YCbCr colorspace
 * to be removed, replacement rte_pixfmt
*/
enum rte_pixformat {
	RTE_YUV420, /* Planar Y:Cb:Cr 1.5 bytes per pixel */
	RTE_YVU420, /* Planar Y:Cr:Cb 1.5 bytes per pixel */
	RTE_YUYV, /* YCbYCr linear, 2 bytes per pixel */
	/* these are the additional formats mp1e supports */
	/* in decimation modes the height of the buffer you have to
	   fill is twice the height of the resulting image */
	RTE_YUYV_VERTICAL_DECIMATION,
	RTE_YUYV_TEMPORAL_INTERPOLATION,
	RTE_YUYV_VERTICAL_INTERPOLATION,
	RTE_YUYV_PROGRESSIVE,
	RTE_YUYV_PROGRESSIVE_TEMPORAL,
	/* experimental, not accelerated, subject to change w/o notice */
	RTE_YUYV_EXP,
	RTE_YUYV_EXP_VERTICAL_DECIMATION,
	RTE_YUYV_EXP2
};

/*
  Video frame rate. From the standard.
 * to be removed, is a codec option
*/
enum rte_frame_rate {
	RTE_RATE_NORATE=0, /* frame rate not set, rte won't encode */
	RTE_RATE_1, /* 23.976 Hz (3-2 pulldown NTSC) */
	RTE_RATE_2, /* 24 Hz (film) */
	RTE_RATE_3, /* 25 Hz (PAL/SECAM or 625/60 video) */
	RTE_RATE_4, /* 29.97 (NTSC) */
	RTE_RATE_5, /* 30 Hz (drop-frame NTSC or component 525/60) */
	RTE_RATE_6, /* 50 Hz (double rate PAL) */
	RTE_RATE_7, /* 59.97 Hz (double rate NTSC) */
	RTE_RATE_8, /* 60 Hz (double rate drop-frame NTSC/component
		       525/60 video) */
};

/*
  Available audio modes
 * to be removed, is a codec option
*/
enum rte_audio_mode {
	RTE_AUDIO_MODE_MONO,
	RTE_AUDIO_MODE_STEREO
	/* mhs: see man page */
	/* fixme: implement */
//	RTE_AUDIO_MODE_DUAL_CHANNEL
};

/*
 * Some numbers about the running encoding process.
 * 
 * 2**31 frames = 828 days at 30 fps
 * 2**64 bytes = 1170000 years at 4 Mbit/s
 * timestamps (double, sec), assumed usec precision
 *  usable until appx. year 2110 (XXX temp results
 *  may suffer from rounding much earlier).
 */
struct rte_status_info {
	long long		processed_frames; /* video frames that went into the encoder */
	long long		dropped_frames;	  /* dropped frames */
	unsigned long long	bytes_out;	  /* compressed bytes written */
};

typedef struct _rte_context_private rte_context_private;

typedef struct rte_context rte_context;

/* will become private */
struct rte_context {
	/* Filename used when creating this context, NULL if unknown */
	char * file_name;
	/* Whether to encode audio only, video only or both */
	enum rte_mux_mode mode;
	/* Format we will encode to */
	char *format;

	/******** video parameters **********/
	/* pixformat the passed video data is in, defaults to YUV420 */
	enum rte_pixformat video_format;
	/* frame size */
	int width, height;

	/* Video frame rate (25 fps (PAL) by default) */
	enum rte_frame_rate video_rate;
	/* output video bits per second, defaults to 2.3 Mbit/s */
	ssize_t output_video_bits;

	/* size in bytes of a complete frame */
	int video_bytes;

	/* motion compensation search range */
	int motion_min, motion_max;
	/* Group of pictures sequence ('I'ntra, forward 'P'redicted,
	   'B'idirectionally predicted), must start with 'I', 1023
	   chars max, defaults to IBBPBBPBBPBB */
	char gop_sequence[1024];

	/******* audio parameters **********/
	/* audio sampling rate in Hz, 44100 by default */
	int audio_rate; 
	/* Audio mode, defaults to Mono */
	enum rte_audio_mode audio_mode;
	/* output audio bits per second, defaults to 80Kbit/s */
	ssize_t output_audio_bits;
	/* size in bytes of an audio frame */
	int audio_bytes;

	/* last error */
	char * error;

	/* Stuff we don't want you to see ;-) */
	rte_context_private * private;
};

/*
  "You have to save this data" callback. Defaults to a disk (stdout)
  write().
  context: Context that created this data.
  data: Pointer to the encoded data.
  size: Size in bytes of the data stored in data
  user_data: Pointer passed to rte_context_new
*/
typedef void (*rteEncodeCallback)(rte_context * context,
				  void * data,
				  ssize_t size,
				  void * user_data);

#define RTE_ENCODE_CALLBACK(function) ((rteEncodeCallback)function)

/*
  "I need seeking to this address" callback. Defaults to a
  lseek(fd, offset, whence)
  context: Context that created this data.
  offset: Position in the file
  whence: Where to start seeking from (see lseek)
  user_data: Whatever you want
  Returns: The offset from the beginning of the file in bytes, or
  (off_t)-1 in case of error. This is the same value as lseek returns
  (see 'man lseek')
*/
typedef off64_t (*rteSeekCallback)(rte_context * context,
				   off64_t offset,
				   int whence,
				   void * user_data);

#define RTE_SEEK_CALLBACK(function) ((rteSeekCallback)function)

/*
  "I need more data" callback. The input thread will call this
  callback whenever it needs some fresh data to encode. The callbacks
  and the push() interfaces shouldn't be used together (rte isn't
  designed with that in mind, but it could work).
  context: The context that asks for the data.
  data: Where should you write the data. It's a memchunk of
  context->video_bytes or context->audio_bytes (depending whether rte
  asks for video or audio), and you should fill it (i.e., a video
  frame of audio_bytes of audio).
  time: Push here the timestamp for your frame.
  stream: What are we requesting (RTE_AUDIO or RTE_VIDEO)
  user_data: User data passed to rte_context_new
*/
typedef void (*rteDataCallback)(rte_context * context,
				void * data,
				double * time,
				enum rte_mux_mode stream,
				void * user_data);

#define RTE_DATA_CALLBACK(function) ((rteDataCallback)function)

/*
 * Struct used for buffered input.
 */
typedef struct {
	void	*data; /* Pointer to the data in the buffer */
	double	time; /* timestamp for the buffer */
	void	*user_data; /* Whatever data the user wants to store */
} rte_buffer;

/*
 * "I need a buffer" callback. The usage is the same as a
 * data callback, but you don't need to do the memcpy.
 * buffer: Buffer the lib will be using for encoding. Set data, time
 *	   and optionally user_data to the correct values.
 * stream: What are we requesting
 */
typedef void (*rteBufferCallback)(rte_context * context,
				  rte_buffer * buffer,
				  enum rte_mux_mode stream);

#define RTE_BUFFER_CALLBACK(function) ((rteBufferCallback)function)

/*
 * Callback used when the encoding engine no longer needs a supplied
 * buffer.
 * The buffer is property of rte, you just need to free whatever data
 * you provided when pushing or giving it through a callback.
 * buffer: The buffer no longer needed by the encoding engine.
 */
typedef void (*rteUnrefCallback)(rte_context * contex,
				 rte_buffer * buffer);

#define RTE_UNREF_CALLBACK(function) ((rteUnrefCallback)function)

/* Interface functions */
/*
  Inits the lib, and it does some checks.
  Returns 1 if the lib can be used in this box, and 0 if not.

  to become a lib constructor (?),
  codecs/formats which won't work in this box won't be enumerated.
*/
int rte_init ( void );

/*
  Creates a rte encoding context. The compulsory parameters are here,
  if the rest aren't specified before pushing data, then the defaults
  are used.
  Returns: The new context on startup, NULL on error.
  width, height: Width and height of the pushed frames, must be 16-multiplus
  **changed**
  user_data: Some data you would like to pass to the callback
*/
rte_context * rte_context_new (int width, int height,
			       void * user_data);

/*
  Destroys the encoding context and (if encoding) stops encoding. It
  frees the memory allocated by the rte_context.
  Returns: Always NULL
*/
#define rte_context_destroy rte_context_delete

/*
 * Sets the a/v input mode for the context.
 * stream: What are we setting (RTE_AUDIO or RTE_VIDEO)
 * interface: interface to use (push or callback)
 * buffered: TRUE if buffering is to be used.
 * *_callback: Supply the appropiate callbacks here (NULL if not needed).
 */
void rte_set_input (rte_context * context,
		    enum rte_mux_mode stream,
		    enum rte_interface interface, int buffered,
		    rteDataCallback data_callback,
		    rteBufferCallback buffer_callback,
		    rteUnrefCallback unref_callback);

/*
 * Sets the what should rte do with the encoded data.
 * encode_callback: Callback when an encoded packet is ready, can be NULL.
 * seek_callback: Callback when the encoder needs moving the dest file
 * pointer, can be NULL.
 * filename: if encode_callback is NULL, put the file where rte will write
 * the data here. No verification is done until the file is opened.
 */
void rte_set_output (rte_context * context,
		     rteEncodeCallback encode_callback,
		     rteSeekCallback seek_callback,
		     const char * filename);

/*
  Setters and getters for the members in the struct, so no direct
  access is needed. Direct access to the struct fields is allowed when
  no getter is provided (this is to avoid API bloat), but you should
  NEVER change a field directly.
*/
/*
 * Asks the current backend for the available formats.
 * n: index of the format we are querying. Starts from 0.
 * mux_mode: If not NULL, the mux mode the format supports will be
 * stored here. Ignored if it's NULL.
 * Returns: NULL if the nth format doesn't exist and a statically
 * allocated string that shouldn't be freed if it exists.
 * will be removed, replaced by rte_context_enum
 */
char * rte_query_format (rte_context * context,
			 int n,
			 enum rte_mux_mode * mux_mode);

/*
 * Sets the encoding format for the context.
 * format: Name of the format, as reported by rte_query_format.
 * Returns: 0 on error.
 * will be removed, replaced by rte_context_new
 */
int rte_set_format (rte_context * context,
		    const char * format);

/*
  Sets the video parameters. If you don't want to change any field of
  these, just pass the current value. For example, if you don't want
  to change the gop sequence, just pass context->gop_sequence.
  will be replaced by codec parameters
*/
int rte_set_video_parameters (rte_context * context,
			      enum rte_pixformat video_format,
			      int width, int height,
			      enum rte_frame_rate video_rate,
			      ssize_t output_video_bits,
			      const char *gop_sequence);

/* Sets the audio parameters, 0 on error
  will be replaced by codec parameters */
int rte_set_audio_parameters (rte_context * context,
			      int audio_rate,
			      enum rte_audio_mode audio_mode,
			      ssize_t output_audio_bits);

/* Specifies whether to encode audio only, video only or both
  will be removed, replaced by rte_codec_set */
void rte_set_mode (rte_context * context, enum rte_mux_mode mode);

/*
  Specifies motion compensation search range,
  min <= max, min = max = 0 = off, in half samples.
  will be removed, is a codec option
 */
void rte_set_motion (rte_context * context, int min, int max);

/* [SG]ets the user data parameter. Can be done while encoding */
void rte_set_user_data(rte_context * context, void * user_data);
void * rte_get_user_data(rte_context * context);

/*
 * Prepares the context for encoding. Must be called before calling
 * start_encoding. Returns 1 on success.
 * will be removed,
    rte_codec_input_<method>(...) puts the codec,
    rte_context_output_<method>(...) the context in ready state.
 */
int rte_init_context ( rte_context * context );

/*
 * If necessary, syncs the audio and video streams and starts
 * encoding. The context must be sucessfully inited before calling
 * this.
 * Returns 1 on success.
 */
int rte_start_encoding ( rte_context * context );

/*
  Stops encoding frames. Usually you won't call this, but
  rte_context_destroy. This has the advantage that the current setting
  are kept, and rte_start can be called again on the same context.
  It flushes output buffers too.
  If you are pushing data from a thread different to the thread this
  is called from, you must make sure the thread has stopped pushing
  before calling this.
*/
void rte_stop ( rte_context * context );

/*
  Pushes a video frame into the given encoding context.
  data: Pointer to the data to encode, it must be a complete frame as
  described in the context.
  time: Timestamp given to the frame, in seconds
  Returns: A pointer to the buffer where you should write the next
  frame. This way a redundant memcpy() is avoided. You can call
  push_video_data with data = NULL to get the first buffer.
  The size allocated for the buffer is in context->video_bytes

  void * ptr = rte_push_video_data(context, NULL, 0);
  do {
  double timestamp;
  get_data_from_video_source(ptr, &timestamp);
  ptr = rte_push_video_data(context, ptr, timestamp);
  } while (data_available);
*/
void * rte_push_video_data ( rte_context * context, void * data,
			     double time );

/*
 * This is the same as push_video_data but it uses buffers, thus saving a
 * memcpy. You should fill in the fields of buffer as needed.
 */
void rte_push_video_buffer ( rte_context * context,
			     rte_buffer * buffer );

/*
  Pushes an audio sample into the given encoding context. The usage is
  similar to push_video_data.
  When you push one sample, it is assumed that it contains
  context->audio_bytes of audio data with the current context audio
  parameters.
  The expected audio format is signed 16-bit Little Endian.
  A sample is structured as follows:
  2 * (stereo ? 1:2) * 1632 bytes of audio, where the first 1152
  audio atoms (2* (stereo ? 1:2) bytes of audio are considered an
  atom) are data, and the remaining 480 atoms belong to the next frame
  (so the last atoms will be pushed in the beginning of the next frame).
  data: pointer to the data to encode.
  time: Timestamp given to the frame, in seconds.
  Returns: A pointer to the buffer where you should write the next sample
*/
void * rte_push_audio_data ( rte_context * context, void * data,
			     double time );

/*
 * This is the same as push_audio_data but it uses buffers, thus saving a
 * memcpy. You should fill in the fields of buffer as needed.
 */
void rte_push_audio_buffer ( rte_context * context,
			     rte_buffer * buffer );

/*
 * Sets the verbosity value.
 */
void rte_set_verbosity ( rte_context * context, int level );

/*
 * Returns the current verbosity value
 */
int rte_get_verbosity ( rte_context * context );

/*
 * Fills in the status structure. If the context isn't encoding the
 * struct is cleared with zeros.
 */
void rte_get_status( rte_context * context,
		     struct rte_status_info * info );

/*
 * Some useful stuff
 */
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

typedef int rte_bool; /* just for documentation */


/*
 *  ** Experimental **
 *  don't use in production code 
 */

/*
 *  Contexts (backends, file formats, multiplexed streams)
 */

typedef enum rte_stream_type {
  RTE_STREAM_VIDEO = 1,  /* XXX STREAM :-( need a better term */
  RTE_STREAM_AUDIO,	 /* input/output distinction? */
  RTE_STREAM_SLICED_VBI,
  /* ... */
  RTE_STREAM_MAX = 15
} rte_stream_type;

typedef struct rte_context_info {
  char *		keyword;	/* eg. "mp1e-mpeg1-ps" */
  
  char *		backend;	/* no NLS b/c proper name */

  char *		label;		/* gettext()ized _N() */
  char *		tooltip;	/* or NULL, gettext()ized _N() */

  /*
   *  Multiple strings allowed, separated by comma. The first
   *  string is preferred. Ex "video/x-mpeg", "mpg,mpeg".
   */
  char *		mime_type;	/* or NULL */
  char *		extension;	/* or NULL */

  /*
   *  Permitted number of elementary streams of each type, for example
   *  MPEG-1 PS: video 16, audio 32, sliced vbi 1, to select rte_codec_set
   *  substream number 0 ... n-1.
   */
  char			elementary[RTE_STREAM_MAX + 1];
} rte_context_info;

// future
// typedef struct rte_context rte_context; /* opaque */

extern rte_context_info *rte_context_info_enum(int);
extern rte_context_info *rte_context_info_keyword(char *);
extern rte_context_info *rte_context_info_context(rte_context *);

extern rte_context *rte_context_new2(void);
extern void rte_context_delete(rte_context *);

/*
 *  Codecs (elementary streams)
 */

typedef struct rte_codec_info {
  rte_stream_type	stream_type;
  char *		keyword;
  char *		label;		/* gettext()ized _N() */
  char *		tooltip;	/* or NULL, gettext()ized _N() */
} rte_codec_info;

typedef struct rte_codec rte_codec; /* opaque */

extern rte_codec_info *rte_codec_info_enum(rte_context *, int);
extern rte_codec_info *rte_codec_info_by_keyword(rte_context *, char *);
extern rte_codec_info *rte_codec_info_by_codec(rte_codec *);

/*** 'set' copies string values, 'get' strings must be free()ed */
extern rte_codec *rte_codec_get(rte_context *, rte_stream_type, int);
extern rte_codec *rte_codec_set(rte_context *, rte_stream_type, int, char *);

/*
 *  Codec options
 */

typedef enum rte_option_type {
  RTE_OPTION_BOOL = 1,
  RTE_OPTION_INT,
  RTE_OPTION_REAL,
  RTE_OPTION_STRING,
  RTE_OPTION_MENU,
} rte_option_type;

typedef union rte_option_value {
  int			num;
  char *		str;		/* gettext()ized _N() */
  double		dbl;
} rte_option_value;

typedef struct rte_option_info {
  rte_option_type	type;
  char *		keyword;
  char *		label;		/* gettext()ized _N() */
  rte_option_value	def;		/* default (reset) */
  rte_option_value	min, max;
  rte_option_value	step;
  union {
    int *                 num;
    char **               str;
    double *              dbl;
  }                     menu;
  int			entries;
  char *		tooltip;	/* or NULL, gettext()ized _N() */
} rte_option_info;

#define RTE_OPTION_BOUNDS_INITIALIZER_(type_, def_, min_, max_, step_)	\
  { type_ = def_ }, { type_ = min_ }, { type_ = max_ }, { type_ = step_ }

#define RTE_OPTION_BOOL_INITIALIZER(key_, label_, def_, tip_)		\
  { RTE_OPTION_BOOL, key_, label_,					\
    RTE_OPTION_BOUNDS_INITIALIZER_(.num, def_, 0, 1, 1),		\
    { .num = NULL }, 0, tip_ }

#define RTE_OPTION_INT_INITIALIZER(key_, label_, def_, min_, max_,	\
  step_, menu_, entries_, tip_) { RTE_OPTION_INT, key_, label_,		\
    RTE_OPTION_BOUNDS_INITIALIZER_(.num, def_, min_, max_, step_),	\
    { .num = menu_ }, entries_, tip_ }

#define RTE_OPTION_REAL_INITIALIZER(key_, label_, def_, min_, max_,	\
  step_, menu_, entries_, tip_) { RTE_OPTION_REAL, key_, label_,	\
    RTE_OPTION_BOUNDS_INITIALIZER_(.dbl, def_, min_, max_, step_),	\
    { .dbl = menu_ }, entries_, tip_ }

#define RTE_OPTION_STRING_INITIALIZER(key_, label_, def_, menu_,	\
  entries_, tip_) { RTE_OPTION_STRING, key_, label_,			\
    RTE_OPTION_BOUNDS_INITIALIZER_(.str, def_, NULL, NULL, NULL),	\
    { .str = menu_ }, entries_, tip_ }

#define RTE_OPTION_MENU_INITIALIZER(key_, label_, def_, menu_,		\
  entries_, tip_) { RTE_OPTION_MENU, key_, label_,			\
    RTE_OPTION_BOUNDS_INITIALIZER_(.num, def_, 0, (entries_) - 1, 1),	\
    { .str = menu_ }, entries_, tip_ }

extern rte_option_info *rte_option_info_enum(rte_codec *, int);
extern rte_option_info *rte_option_info_by_keyword(rte_codec *, char *);

/*** 'set' copies string values, 'get' and 'print' strings must be free()ed */
extern rte_bool rte_option_get(rte_codec *, char *, rte_option_value *);
extern rte_bool rte_option_set(rte_codec *, char *, ...);
extern rte_bool rte_option_get_menu(rte_codec *, char *, int *);
extern rte_bool rte_option_set_menu(rte_codec *, char *, int);
extern char *rte_option_print(rte_codec *, char *, ...);

/*
 *  Source parameters
 */

typedef enum rte_pixfmt {
  RTE_PIXFMT_YUV420 = 1,
  RTE_PIXFMT_YUYV,
  RTE_PIXFMT_YVYU,
  RTE_PIXFMT_UYVY,
  RTE_PIXFMT_VYUY,
  RTE_PIXFMT_RGB32,
  RTE_PIXFMT_BGR32,
  RTE_PIXFMT_RGB24,
  RTE_PIXFMT_BGR24,
  RTE_PIXFMT_RGB16,
  RTE_PIXFMT_BGR16,
  RTE_PIXFMT_RGB15,
  RTE_PIXFMT_BGR15,
  /* ... */
  RTE_PIXFMT_MAX = 31
} rte_pixfmt;

typedef enum rte_sndfmt {
  RTE_SNDFMT_S8 = 1,
  RTE_SNDFMT_U8,
  RTE_SNDFMT_S16LE,
  RTE_SNDFMT_S16BE,
  RTE_SNDFMT_U16LE,
  RTE_SNDFMT_U16BE,
  /* ... */
  RTE_SNDFMT_MAX = 31
} rte_sndfmt;

typedef enum rte_vbifmt {
  RTE_VBIFMT_TELETEXT_B_L10_625 = 1,
  RTE_VBIFMT_TELETEXT_B_L25_625,
  RTE_VBIFMT_VPS,
  RTE_VBIFMT_CAPTION_625_F1,
  RTE_VBIFMT_CAPTION_625,
  RTE_VBIFMT_CAPTION_525_F1,
  RTE_VBIFMT_CAPTION_525,
  RTE_VBIFMT_2xCAPTION_525,
  RTE_VBIFMT_NABTS,
  RTE_VBIFMT_TELETEXT_BD_525,
  RTE_VBIFMT_WSS_625,
  RTE_VBIFMT_WSS_CPR1204,
  /* ... */
  RTE_VBIFMT_RESERVED1 = 30,
  RTE_VBIFMT_RESERVED2 = 31
} rte_vbifmt;

#define RTE_VBIFMTS_TELETEXT_B_L10_625	(1UL << RTE_VBIFMT_TELETEXT_B_L10_625)
#define RTE_VBIFMTS_TELETEXT_B_L25_625	(1UL << RTE_VBIFMT_TELETEXT_B_L25_625)
#define RTE_VBIFMTS_VPS			(1UL << RTE_VBIFMT_VPS)
#define RTE_VBIFMTS_CAPTION_625_F1	(1UL << RTE_VBIFMT_CAPTION_625_F1)
#define RTE_VBIFMTS_CAPTION_625		(1UL << RTE_VBIFMT_CAPTION_625)
#define RTE_VBIFMTS_CAPTION_525_F1	(1UL << RTE_VBIFMT_CAPTION_525_F1)
#define RTE_VBIFMTS_CAPTION_525		(1UL << RTE_VBIFMT_CAPTION_525)
#define RTE_VBIFMTS_2xCAPTION_525	(1UL << RTE_VBIFMT_2xCAPTION_525)
#define RTE_VBIFMTS_NABTS		(1UL << RTE_VBIFMT_NABTS)
#define RTE_VBIFMTS_TELETEXT_BD_525	(1UL << RTE_VBIFMT_TELETEXT_BD_525)
#define RTE_VBIFMTS_WSS_625		(1UL << RTE_VBIFMT_WSS_625)
#define RTE_VBIFMTS_WSS_CPR1204		(1UL << RTE_VBIFMT_WSS_CPR1204)
#define RTE_VBIFMTS_RESERVED1		(1UL << RTE_VBIFMT_RESERVED1)
#define RTE_VBIFMTS_RESERVED2		(1UL << RTE_VBIFMT_RESERVED2)

typedef union rte_stream_parameters {
  struct rte_video_stream_parameters {
    rte_pixfmt	          pixfmt;
    double		  frame_rate;	    /* 24, 25, 30, 1001 / 30000, .. */
    int                   width, height;    /* pixels, Y if YUV 4:2:0 */
    int		          u_offset, v_offset; /* bytes rel. Y org or ignored */
    int		          stride;	    /* bytes, Y if YUV 4:2:0 */
    int		          uv_stride;	    /* bytes or ignored */
    /* scaling? */
  }			video;
  struct rte_audio_stream_parameters {
    rte_sndfmt		  sndfmt;
    int			  sampling_freq;	/* Hz */
    int			  channels;		/* mono: 1, stereo: 2 */
    int			  fragment_size;	/* bytes */
  }			audio;
  char			pad[128];
} rte_stream_parameters;

/* read-write */
extern rte_bool rte_set_parameters(rte_codec *, rte_stream_parameters *);

#endif

--- NEW FILE ---
/*
 *  Exported prototypes, they are needed by rte
 *
 *  Copyright (C) 2000 Iñaki G.E.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) version 2.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#ifndef __MAIN_H__
#define __MAIN_H__

/* fixme: leave only neccessary prototypes */

extern double		video_stop_time;
extern double		audio_stop_time;

extern pthread_t	audio_thread_id;
extern int		stereo;

extern pthread_t	video_thread_id;
extern void		(* video_start)(void);

extern pthread_t        output_thread_id;

extern pthread_t	tk_main_id;
extern void *		tk_main(void *);

extern int		mux_mode;
extern int		psycho_loops;

extern void options(int ac, char **av);

extern void preview_init(void);

#include "systems/libsystems.h"

extern volatile int program_shutdown;

#endif // MAIN.H

--- NEW FILE ---
/*
 *  MPEG-1 Real Time Encoder
 *
 *  Copyright (C) 1999-2001 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: options.h,v 1.1 2001/12/04 23:53:53 mswitch Exp $ */

extern int		test_mode;

extern char *		cap_dev;
extern char *		pcm_dev;
extern char *		mix_dev;
extern char *		vbi_dev;

/* Video */

extern int		width;
extern int		height;
extern int		grab_width;
extern int		grab_height;
extern int		video_bit_rate;
extern long long	video_num_frames;
extern char *		gop_sequence;
// extern int		frames_per_seqhdr;
extern int		filter_mode;
extern double		frame_rate;
extern int		preview;
extern char *		anno;
extern int		luma_only;
extern int		motion_min;
extern int		motion_max;
extern int		skip_method;

/* Audio */

extern int		audio_bit_rate;
extern int		audio_bit_rate_stereo;
extern long long	audio_num_frames;
extern int		sampling_rate;
extern int		mix_line;
extern int		mix_volume;
extern int		audio_mode;
extern int		psycho_loops;
extern int		mute; // bttv specific

/* VBI */

extern char *		subtitle_pages;

/* Multiplexer */

#define MOD_VIDEO	0x01
#define MOD_AUDIO	0x02
#define MOD_SUBTITLES	0x04

extern int		modules;
extern int		mux_syn;

extern int		cap_buffers;
extern int		vid_buffers;
extern int		aud_buffers;

extern int		cpu_type;


--- NEW FILE ---
/*
 *  Real Time Encoder lib
 *
 *  Copyright (C) 2000-2001 Iñaki García Etxebarria
 *  Modified 2001 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
[...1335 lines suppressed...]
	r = b_mp1e_info.option_print(codec, keyword, args);

	va_end(args);

	return r;
}

int
rte_set_parameters(rte_codec *codec, rte_stream_parameters *rsp)
{
	rte_context *context = NULL;

	nullcheck(codec, return 0);
	nullcheck((context = codec->context), return 0);

	if (!b_mp1e_info.parameters)
		return 0;

	return b_mp1e_info.parameters(codec, rsp);
}

--- NEW FILE ---
/*
 *  MPEG-1 Real Time Encoder lib wrapper api
 *
 *  Copyright (C) 2000 Iñaki García Etxebarria
 *  Modified 2001 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
 * $Id: rtepriv.h,v 1.1 2001/12/04 23:53:53 mswitch Exp $
 * Private stuff in the context.
 */

#ifndef MP1ERTEPRIV_H
#define MP1ERTEPRIV_H
#include "libmp1e.h"
#include <pthread.h>
#include <stdarg.h>

#define BLANK_BUFFER	1 /* the buffer was created by blank_callback,
			     do not unref_callback it */

typedef void (*_rte_filter)(const char * src, char * dest, int width,
			    int height);

/* for the sake of clarity, prototype of wait_data in rte.c */
typedef void (*_wait_data)(rte_context *context, int video);






/* Experimental */

/* maybe one should add this stuff under a #ifdef RTE_BACKEND to rte.h? */

typedef struct rte_context_class rte_context_class;

struct rte_context_class {
	rte_context_class *	next;
	rte_context_info	public;

	/* ? */

	rte_codec_info *	(* codec_enum)(rte_context *, int);
	rte_codec *		(* codec_get)(rte_context *, rte_stream_type, int);
	rte_codec *		(* codec_set)(rte_context *, rte_stream_type, int, char *);

	rte_option_info *	(* option_enum)(rte_codec *, int);
	int			(* option_get)(rte_codec *, char *, rte_option_value *);
	int			(* option_set)(rte_codec *, char *, va_list);
	char *			(* option_print)(rte_codec *, char *, va_list);

	int			(* parameters)(rte_codec *, rte_stream_parameters *);
};

typedef struct rte_codec_class rte_codec_class;

struct rte_codec_class {
	rte_codec_class *	next;
	rte_codec_info		public;

	/*
	 *  Allocate new codec instance. All fields zero except
	 *  rte_codec.class, .status (RTE_STATUS_NEW), .mutex (initialized),
	 *  and all codec properties reset to defaults.
	 */
	rte_codec *		(* new)(void);
	void			(* delete)(rte_codec *);

	rte_option_info *	(* option_enum)(rte_codec *, int index);
	int			(* option_get)(rte_codec *, char *, rte_option_value *);
	int			(* option_set)(rte_codec *, char *, va_list);
	char *			(* option_print)(rte_codec *, char *, va_list);

	int			(* parameters)(rte_codec *, rte_stream_parameters *);

	/* result unused (yet) */
	void *			(* mainloop)(void *rte_codec);
};

typedef enum rte_codec_status {
	/* new -> */
	RTE_STATUS_NEW = 1,
	RTE_STATUS_RESERVED2,
	/* accept options,
           sample parameters -> */
	RTE_STATUS_PARAM,
	/* option change -> RTE_STATUS_NEW,
           params change -> RTE_STATUS_PARAM,
           i/o -> */
	RTE_STATUS_READY,
	RTE_STATUS_RESERVED5,
	RTE_STATUS_RESERVED6,
	/* option change -> RTE_STATUS_NEW,
	   params change -> RTE_STATUS_PARAM,
	   i/o change -> RTE_STATUS_READY,
           start -> */
	RTE_STATUS_RUNNING,
	RTE_STATUS_RESERVED8,
	/* stop -> */
	RTE_STATUS_STOPPED,
	/* ? -> ? */
	RTE_STATUS_RESERVED10,
} rte_codec_status;

struct rte_codec {
	rte_codec *		next;

	rte_context *		context;	/* parent context */
	rte_codec_class *	class;		/* read only */

	int			stream;		/* multiplexer substream */

	pthread_mutex_t		mutex;		/* locked by class funcs */

	rte_codec_status	status;		/* mutex protected, read only */

	/* Valid when RTE_STATUS_RUNNING; mutex protected, read only. */
	int64_t			frame_input_count;
	int64_t			frame_input_missed;	/* excl. intent. skipped */
	int64_t			frame_output_count;
	int64_t			byte_output_count;
	double			coded_time_elapsed;
	// XXX?
	double			frame_output_rate;	/* invariable, 1/s */

	/* append codec private stuff */
};



typedef struct {
	char		*name;
	int		priv_size; /* sizeof(*context->priv)+backend data */
	/* basic backend functions */
	int		(*init_backend)(void);
	/* Init backend specific structs and context->format with trhe
	 default format */
	void		(*context_new)(rte_context * context);
	/* Free context specific structs and context->format */
	void		(*context_destroy)(rte_context * context);
	int		(*pre_init_context)(rte_context * context);
	int		(*post_init_context)(rte_context * context);
	void		(*uninit_context)(rte_context * context);
	int		(*start)(rte_context * context);
	void		(*stop)(rte_context * context);
	char*		(*query_format)(rte_context *context,
					int n,
					enum rte_mux_mode *mux_mode);
	void		(*status)(rte_context * context,
				  struct rte_status_info *status);

	/* Experimental */

	rte_context_info *	(* context_enum)(int);
	rte_context *		(* context_new2)(char *);
	void			(* context_delete)(rte_context *);

	/* tbd context_class */

	rte_codec_info *	(* codec_enum)(rte_context *, int);
	rte_codec *		(* codec_get)(rte_context *, rte_stream_type, int);
	rte_codec *		(* codec_set)(rte_context *, rte_stream_type, int, char *);

	rte_option_info *	(* option_enum)(rte_codec *, int);
	int			(* option_get)(rte_codec *, char *, rte_option_value *);
	int			(* option_set)(rte_codec *, char *, va_list);
	char *			(* option_print)(rte_codec *, char *, va_list);

	int			(* parameters)(rte_codec *, rte_stream_parameters *);

} rte_backend_info;


#define RC(X) ((rte_context*)X)

#define rte_error(context, format, args...) \
{ \
	if (context) { \
		if (!RC(context)->error) \
			RC(context)->error = malloc(256); \
		RC(context)->error[255] = 0; \
		snprintf(RC(context)->error, 255, \
			 "rte:%s:%s(%d): " format, \
			 __FILE__, __PRETTY_FUNCTION__, __LINE__ ,##args); \
	} \
	else \
		fprintf(stderr, "rte:%s:%s(%d): " format ".\n", \
			__FILE__, __PRETTY_FUNCTION__, __LINE__ ,##args); \
}

/*
  Private things we don't want people to see, we can play with this
  without breaking any compatibility.
  Eventually all the global data will move here, except for the
  tables.
*/
struct _rte_context_private {
	int encoding; /* 0 if not encoding */
	int inited; /* 0 if not inited */
	int backend; /* backend to be used */
	rteEncodeCallback encode_callback; /* save-data Callback */
	rteSeekCallback seek_callback; /* seek in file callback */
	rteDataCallback audio_data_callback; /* need audio data */
	rteDataCallback video_data_callback; /* need video data */
	rteBufferCallback audio_buffer_callback; /* need audio buffer */
	rteBufferCallback video_buffer_callback; /* need video buffer */
	rteUnrefCallback audio_unref_callback; /* audio release */
	rteUnrefCallback video_unref_callback; /* video release */
	enum rte_interface audio_interface; /* audio interface */
	enum rte_interface video_interface; /* video interface */
	int audio_buffered; /* whether the audio uses buffers or memcpy */
	int video_buffered; /* whether the video uses buffers or memcpy */
	int fd64; /* file descriptor of the file we are saving */
	void * user_data; /* user data given to the callback */
	fifo vid, aud; /* callback fifos for pushing */
	producer vid_prod, aud_prod;
	int depth; /* video bit depth (bytes per pixel, includes
		      packing) */
	buffer * last_video_buffer; /* video buffer the app should be
				       encoding to */
	buffer * last_audio_buffer; /* audio buffer */
	unsigned long long bytes_out; /* sent bytes */

	rte_context_class *	class;
};

/*
 *  Helper functions
 *
 *  (note the backend is bypassed, may change)
 */

#define nullcheck(X, whattodo)						\
do {									\
	if (!X) {							\
		rte_error(NULL, #X " == NULL");				\
		whattodo;						\
	}								\
} while (0)

static inline int
rte_helper_set_option_va(rte_codec *codec, char *keyword, ...)
{
	va_list args;
	int r;

	va_start(args, keyword);
	r = codec->class->option_set(codec, keyword, args);
	va_end(args);

	return r;
}

static inline int
rte_helper_reset_options(rte_codec *codec)
{
	rte_option_info *option;
	int r = 1, i = 0;

	while (r && (option = codec->class->option_enum(codec, i++))) {
		switch (option->type) {
		case RTE_OPTION_INT:
		case RTE_OPTION_BOOL:
		case RTE_OPTION_MENU:
			r = rte_helper_set_option_va(
				codec, option->keyword, option->def.num);
			break;
		case RTE_OPTION_STRING:
			r = rte_helper_set_option_va(
				codec, option->keyword, option->def.str);
			break;
		case RTE_OPTION_REAL:
			r = rte_helper_set_option_va(
				codec, option->keyword, option->def.dbl);
			break;
		default:
			assert(!"reset option->type");
		}
	}

	return r;
}

#endif



--- NEW FILE ---
/* Site specific definitions */

#ifndef SITE_DEF_H

#define VERSION "1.9.2"

#define SITE_DEF_H
#endif /* SITE_DEF_H */




More information about the MPlayer-cvslog mailing list