AC_CHECK_HEADER(encore2.h, ,
[ AC_MSG_WARN([Divx4linux encore headers not found]) &&
HAVE_DIVX=no ] )
- AC_CHECK_HEADER(decore.h, ,
- [ AC_MSG_WARN([Divx4linux decoder headers not found]) &&
- HAVE_DIVX=no ] )
+ if [ test x$HAVE_DIVX = xyes ]; then
+ AC_MSG_CHECKING([Checking for valid divx4linux encore version])
+ AC_TRY_COMPILE([
+#include <encore2.h>
+#if ENCORE_VERSION != 20021024
+#error Wrong version of divx encore libraries
+#endif
+ ], [
+return 0;
+ ], [ HAVE_DIVX=yes && AC_MSG_RESULT(yes)],
+ [ HAVE_DIVX=no && AC_MSG_RESULT(no) &&
+ AC_MSG_WARN([Wrong version of divx4linux installed]) ])
+ fi
+ if [ test x$HAVE_DIVX = xyes ]; then
+ AC_CHECK_HEADER(decore.h, ,
+ [ AC_MSG_WARN([Divx4linux decoder headers not found]) &&
+ HAVE_DIVX=no ] )
+ fi
+ if [ test x$HAVE_DIVX = xyes ]; then
+ AC_MSG_CHECKING([Checking for valid divx4linux decore version])
+ AC_TRY_COMPILE([
+#include <decore.h>
+#if DECORE_VERSION != 20021112
+#error Wrong version of divx decore libraries
+#endif
+ ], [
+return 0;
+ ], [ HAVE_DIVX=yes && AC_MSG_RESULT(yes)],
+ [ HAVE_DIVX=no && AC_MSG_RESULT(no) &&
+ AC_MSG_WARN([Wrong version of divx4linux installed]) ])
+ fi
LIBS="-lm"
- AC_CHECK_LIB(divxencore, encore, ,
- [ AC_MSG_WARN([Divx4linux encore libs not found]) &&
- HAVE_DIVX=no ] )
- AC_CHECK_LIB(divxdecore, decore, ,
- [ AC_MSG_WARN([Divx4linux decore libs not found]) &&
- HAVE_DIVX=no ] )
+ if test x$HAVE_DIVX = xyes; then
+ AC_CHECK_LIB(divxencore, encore, ,
+ [ AC_MSG_WARN([Divx4linux encore libs not found]) &&
+ HAVE_DIVX=no ] )
+ fi
+ if test x$HAVE_DIVX = xyes; then
+ AC_CHECK_LIB(divxdecore, decore, ,
+ [ AC_MSG_WARN([Divx4linux decore libs not found]) &&
+ HAVE_DIVX=no ] )
+ fi
if test x$HAVE_DIVX = xyes; then
DIVXENC_LIBS="-ldivxencore -lm"
DIVXDEC_LIBS="-ldivxdecore -lm"
/* static guint gst_divxdec_signals[LAST_SIGNAL] = { 0 }; */
+static gchar *
+gst_divxdec_error (int errorcode)
+{
+ gchar *error;
+
+ switch (errorcode) {
+ case DEC_OK:
+ error = "No error";
+ break;
+ case DEC_MEMORY:
+ error = "Invalid memory";
+ break;
+ case DEC_BAD_FORMAT:
+ error = "Invalid format";
+ break;
+ case DEC_INVALID_ARGUMENT:
+ error = "Invalid argument";
+ break;
+ case DEC_NOT_IMPLEMENTED:
+ error = "Not implemented";
+ break;
+ default:
+ error = "Unknown error";
+ break;
+ }
+
+ return error;
+}
+
GType
gst_divxdec_get_type(void)
{
gst_element_add_pad(GST_ELEMENT(divxdec), divxdec->srcpad);
/* bitrate, etc. */
- divxdec->width = divxdec->height = divxdec->csp = -1;
+ divxdec->width = divxdec->height = divxdec->csp = divxdec->bitcnt = -1;
/* set divx handle to NULL */
divxdec->handle = NULL;
static void
gst_divxdec_unset (GstDivxDec *divxdec)
{
- /* free allocated memory */
- g_free(divxdec->bufinfo.mp4_edged_ref_buffers);
- g_free(divxdec->bufinfo.mp4_edged_for_buffers);
- g_free(divxdec->bufinfo.mp4_edged_back_buffers);
- g_free(divxdec->bufinfo.mp4_display_buffers);
- g_free(divxdec->bufinfo.mp4_state);
- g_free(divxdec->bufinfo.mp4_tables);
- g_free(divxdec->bufinfo.mp4_stream);
- g_free(divxdec->bufinfo.mp4_reference);
-
if (divxdec->handle) {
/* unref this instance */
- decore((gulong) divxdec->handle, DEC_OPT_RELEASE,
- NULL, NULL);
+ decore(divxdec->handle, DEC_OPT_RELEASE, NULL, NULL);
divxdec->handle = NULL;
}
}
static gboolean
gst_divxdec_setup (GstDivxDec *divxdec)
{
- DEC_PARAM xdec;
- DEC_MEM_REQS xreq;
+ void *handle;
+ DEC_INIT xinit;
+ DivXBitmapInfoHeader output;
int ret;
- /* initialise parameters, see divx documentation */
- memset(&xdec, 0, sizeof(DEC_PARAM));
- xdec.x_dim = divxdec->width;
- xdec.y_dim = divxdec->height;
- xdec.time_incr = 15; /* default - what is this? */
- xdec.output_format = divxdec->csp;
-
- if ((ret = decore((gulong) divxdec, DEC_OPT_MEMORY_REQS,
- &xdec, &xreq)) != 0) {
- char *error;
- switch (ret) {
- case DEC_MEMORY:
- error = "Memory allocation error";
- break;
- case DEC_BAD_FORMAT:
- error = "Format";
- break;
- default:
- error = "Internal failure";
- break;
- }
- GST_DEBUG(GST_CAT_PLUGIN_INFO,
- "Setting parameters %dx%d@%d failed: %s",
- divxdec->width, divxdec->height, divxdec->csp, error);
+ /* initialize the handle */
+ memset(&xinit, 0, sizeof(DEC_INIT));
+ if ((ret = decore(&handle, DEC_OPT_INIT, &xinit, NULL)) != 0) {
+ gst_element_error(GST_ELEMENT(divxdec),
+ "Error initializing divx decoding library: %s (%d)",
+ gst_divxdec_error(ret), ret);
return FALSE;
}
- /* allocate memory */
- xdec.buffers.mp4_edged_ref_buffers = g_malloc(xreq.mp4_edged_ref_buffers_size);
- memset(xdec.buffers.mp4_edged_ref_buffers, 0, xreq.mp4_edged_ref_buffers_size);
-
- xdec.buffers.mp4_edged_for_buffers = g_malloc(xreq.mp4_edged_for_buffers_size);
- memset(xdec.buffers.mp4_edged_for_buffers, 0, xreq.mp4_edged_for_buffers_size);
-
- xdec.buffers.mp4_edged_back_buffers = g_malloc(xreq.mp4_edged_back_buffers_size);
- memset(xdec.buffers.mp4_edged_back_buffers, 0, xreq.mp4_edged_back_buffers_size);
-
- xdec.buffers.mp4_display_buffers = g_malloc(xreq.mp4_display_buffers_size);
- memset(xdec.buffers.mp4_display_buffers, 0, xreq.mp4_display_buffers_size);
+ /* we've got a handle now */
+ divxdec->handle = handle;
- xdec.buffers.mp4_state = g_malloc(xreq.mp4_state_size);
- memset(xdec.buffers.mp4_state, 0, xreq.mp4_state_size);
-
- xdec.buffers.mp4_tables = g_malloc(xreq.mp4_tables_size);
- memset(xdec.buffers.mp4_tables, 0, xreq.mp4_tables_size);
-
- xdec.buffers.mp4_stream = g_malloc(xreq.mp4_stream_size);
- memset(xdec.buffers.mp4_stream, 0, xreq.mp4_stream_size);
-
- xdec.buffers.mp4_reference = g_malloc(xreq.mp4_reference_size);
- memset(xdec.buffers.mp4_reference, 0, xreq.mp4_reference_size);
-
- divxdec->bufinfo = xdec.buffers;
-
- if ((ret = decore((gulong) divxdec, DEC_OPT_INIT,
- &xdec, &xreq)) != 0) {
+ /* initialise parameters, see divx documentation */
+ memset(&output, 0, sizeof(DivXBitmapInfoHeader));
+ output.biSize = sizeof(DivXBitmapInfoHeader);
+ output.biWidth = divxdec->width;
+ output.biHeight = divxdec->height;
+ output.biBitCount = divxdec->bitcnt;
+ output.biCompression = divxdec->csp;
+
+ if ((ret = decore(divxdec->handle, DEC_OPT_SETOUT,
+ &output, NULL)) != 0) {
gst_element_error(GST_ELEMENT(divxdec),
- "Expected error when confirming current settings: %d",
- ret);
+ "Error setting output format: %s (%d)",
+ gst_divxdec_error(ret), ret);
gst_divxdec_unset(divxdec);
return FALSE;
}
- /* don't tell me this sucks - this is how divx4linux works... */
- divxdec->handle = divxdec;
-
return TRUE;
}
xframe.bitstream = (void *) GST_BUFFER_DATA(buf);
xframe.bmp = (void *) GST_BUFFER_DATA(outbuf);
xframe.length = GST_BUFFER_SIZE(buf);
- xframe.stride = divxdec->width * divxdec->bpp / 8;
+ xframe.stride = 0;
xframe.render_flag = 1;
- if ((ret = decore((gulong) divxdec->handle, DEC_OPT_FRAME,
+ if ((ret = decore(divxdec->handle, DEC_OPT_FRAME,
&xframe, NULL))) {
gst_element_error(GST_ELEMENT(divxdec),
- "Error decoding divx frame: %d\n", ret);
+ "Error decoding divx frame: %s (%d)",
+ gst_divxdec_error(ret), ret);
gst_buffer_unref(buf);
return;
}
struct {
guint32 fourcc;
gint depth, bpp;
- gint csp;
+ guint32 csp;
+ gint bitcnt;
} fmt_list[] = {
- { GST_MAKE_FOURCC('Y','U','Y','V'), 16, 16, DEC_YUY2 },
- { GST_MAKE_FOURCC('U','Y','V','Y'), 16, 16, DEC_UYVY },
- { GST_MAKE_FOURCC('I','4','2','0'), 12, 12, DEC_420 },
- { GST_MAKE_FOURCC('I','Y','U','V'), 12, 12, DEC_420 },
- { GST_MAKE_FOURCC('Y','V','1','2'), 12, 12, DEC_YV12 },
- { GST_MAKE_FOURCC('R','G','B',' '), 32, 32, DEC_RGB32 },
- { GST_MAKE_FOURCC('R','G','B',' '), 24, 24, DEC_RGB24 },
- { GST_MAKE_FOURCC('R','G','B',' '), 16, 16, DEC_RGB555 },
- { GST_MAKE_FOURCC('R','G','B',' '), 15, 16, DEC_RGB565 },
- { 0, 0, 0 }
+ { GST_MAKE_FOURCC('Y','U','Y','2'), 16, 16,
+ GST_MAKE_FOURCC('Y','U','Y','2'), 0 },
+ { GST_MAKE_FOURCC('U','Y','V','Y'), 16, 16,
+ GST_MAKE_FOURCC('U','Y','V','Y'), 0 },
+ { GST_MAKE_FOURCC('I','4','2','0'), 12, 12,
+ GST_MAKE_FOURCC('I','4','2','0'), 0 },
+ { GST_MAKE_FOURCC('I','Y','U','V'), 12, 12,
+ GST_MAKE_FOURCC('I','4','2','0'), 0 },
+ { GST_MAKE_FOURCC('Y','V','1','2'), 12, 12,
+ GST_MAKE_FOURCC('Y','V','1','2'), 0 },
+ { GST_MAKE_FOURCC('R','G','B',' '), 32, 32,
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ GST_MAKE_FOURCC('A','B','G','R'), 32 },
+#else
+ 0, 32 },
+#endif
+ { GST_MAKE_FOURCC('R','G','B',' '), 24, 24,
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ GST_MAKE_FOURCC('A','B','G','R'), 24 },
+#else
+ 0, 24 },
+#endif
+ { GST_MAKE_FOURCC('R','G','B',' '), 16, 16,
+ 3, 16 },
+ { GST_MAKE_FOURCC('R','G','B',' '), 15, 16,
+ 0, 16 },
+ { 0, 0, 0, 0, 0 }
};
gint i;
}
if (gst_pad_try_set_caps(divxdec->srcpad, caps) > 0) {
- divxdec->csp = fmt_list[i].csp;
- divxdec->bpp = fmt_list[i].bpp;
+ divxdec->csp = fmt_list[i].csp;
+ divxdec->bpp = fmt_list[i].bpp;
+ divxdec->bitcnt = fmt_list[i].bitcnt;
if (gst_divxdec_setup(divxdec))
return GST_PAD_LINK_OK;
}
GstPlugin *plugin)
{
GstElementFactory *factory;
+ int lib_version;
+
+ lib_version = decore(NULL, DEC_OPT_VERSION, 0, 0);
+ if (lib_version != DECORE_VERSION) {
+ g_warning("Version mismatch! This plugin was compiled for "
+ "DivX version %d, while your library has version %d!",
+ DECORE_VERSION, lib_version);
+ return FALSE;
+ }
/* create an elementfactory for the v4lmjpegsrcparse element */
factory = gst_element_factory_new("divxdec", GST_TYPE_DIVXDEC,
/* divx handle */
void *handle;
- DEC_BUFFERS bufinfo;
/* video (output) settings */
- int csp, bpp;
+ guint32 csp;
+ int bitcnt, bpp;
int width, height;
};
ARG_0,
ARG_BITRATE,
ARG_MAXKEYINTERVAL,
- ARG_BUFSIZE
+ ARG_BUFSIZE,
+ ARG_QUALITY
};
static guint gst_divxenc_signals[LAST_SIGNAL] = { 0 };
+static gchar *
+gst_divxenc_error (int errorcode)
+{
+ gchar *error;
+
+ switch (errorcode) {
+ case ENC_BUFFER:
+ error = "Invalid buffer";
+ break;
+ case ENC_FAIL:
+ error = "Operation failed";
+ break;
+ case ENC_OK:
+ error = "No error";
+ break;
+ case ENC_MEMORY:
+ error = "Bad memory location";
+ break;
+ case ENC_BAD_FORMAT:
+ error = "Invalid format";
+ break;
+ case ENC_INTERNAL:
+ error = "Internal error";
+ break;
+ default:
+ error = "Unknown error";
+ break;
+ }
+
+ return error;
+}
+
+
GType
gst_divxenc_get_type(void)
{
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
g_param_spec_ulong("buffer_size", "Buffer Size",
"Size of the video buffers",
- 0,G_MAXULONG,0,G_PARAM_READWRITE));
+ 0,G_MAXULONG,0,G_PARAM_READABLE));
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_QUALITY,
+ g_param_spec_int("quality", "Quality",
+ "Amount of Motion Estimation",
+ 1,5,3,G_PARAM_READWRITE));
gobject_class->set_property = gst_divxenc_set_property;
gobject_class->get_property = gst_divxenc_get_property;
gst_element_add_pad(GST_ELEMENT(divxenc), divxenc->srcpad);
/* bitrate, etc. */
- divxenc->width = divxenc->height = divxenc->csp = -1;
+ divxenc->width = divxenc->height = divxenc->csp = divxenc->bitcnt = -1;
divxenc->bitrate = 512 * 1024;
divxenc->max_key_interval = -1; /* default - 2*fps */
divxenc->buffer_size = 512 * 1024;
+ divxenc->quality = 3;
/* set divx handle to NULL */
divxenc->handle = NULL;
static gboolean
gst_divxenc_setup (GstDivxEnc *divxenc)
{
- ENC_PARAM xenc;
+ void *handle;
+ SETTINGS output;
+ DivXBitmapInfoHeader input;
gdouble fps;
int ret;
fps = gst_video_frame_rate(GST_PAD_PEER(divxenc->sinkpad));
/* set it up */
- memset(&xenc, 0, sizeof(ENC_PARAM));
- xenc.x_dim = divxenc->width;
- xenc.y_dim = divxenc->height;
- xenc.framerate = fps;
-
- xenc.rc_period = 2000;
- xenc.rc_reaction_period = 10;
- xenc.rc_reaction_ratio = 20;
-
- xenc.max_quantizer = 31;
- xenc.min_quantizer = 1;
-
- xenc.quality = 3;
- xenc.bitrate = divxenc->bitrate;
-
- xenc.deinterlace = 0;
-
- xenc.max_key_interval = (divxenc->max_key_interval == -1) ?
- (2 * xenc.framerate) :
- divxenc->max_key_interval;
- xenc.handle = NULL;
-
- if ((ret = encore(NULL, ENC_OPT_INIT, &xenc, NULL))) {
+ memset(&input, 0, sizeof(DivXBitmapInfoHeader));
+ input.biSize = sizeof(DivXBitmapInfoHeader);
+ input.biWidth = divxenc->width;
+ input.biHeight = divxenc->height;
+ input.biBitCount = divxenc->bitcnt;
+ input.biCompression = divxenc->csp;
+
+ memset(&output, 0, sizeof(SETTINGS));
+ output.vbr_mode = 0;
+ output.bitrate = divxenc->bitrate;
+ output.quantizer = 0;
+ output.use_bidirect = 0;
+ output.input_clock = 0;
+ output.input_frame_period = 1000000;
+ output.internal_timescale = fps * 1000000;
+ output.max_key_interval = (divxenc->max_key_interval == -1) ?
+ (2 * fps) :
+ divxenc->max_key_interval;
+ output.key_frame_threshold = 0;
+ output.vbv_bitrate = 0;
+ output.vbv_size = 0;
+ output.vbv_occupancy = 0;
+ output.complexity_modulation = 0;
+ output.deinterlace = 0;
+ output.quality = divxenc->quality;
+ output.data_partitioning = 0;
+ output.quarter_pel = 0;
+ output.use_gmc = 0;
+ output.psychovisual = 0;
+ output.pv_strength_frame = 0;
+ output.pv_strength_MB = 0;
+ output.interlace_mode = 0;
+ output.enable_crop = 0;
+ output.enable_resize = 0;
+ output.temporal_enable = 0;
+ output.spatial_passes = 0;
+
+ if ((ret = encore(&handle, ENC_OPT_INIT, &input, &output))) {
gst_element_error(GST_ELEMENT(divxenc),
- "Error setting up divx encoder: %d\n",
- ret);
+ "Error setting up divx encoder: %s (%d)",
+ gst_divxenc_error(ret), ret);
return FALSE;
}
- divxenc->handle = xenc.handle;
+ divxenc->handle = handle;
+
+ /* set buffer size to theoretical limit (see docs on divx.com) */
+ divxenc->buffer_size = 6 * divxenc->width * divxenc->height;
return TRUE;
}
static void
gst_divxenc_unset (GstDivxEnc *divxenc)
{
- encore(divxenc->handle, ENC_OPT_RELEASE, NULL, NULL);
- divxenc->handle = NULL;
+ if (divxenc->handle) {
+ encore(divxenc, ENC_OPT_RELEASE, NULL, NULL);
+ divxenc->handle = NULL;
+ }
}
xframe.image = GST_BUFFER_DATA(buf);
xframe.bitstream = (void *) GST_BUFFER_DATA(outbuf);
xframe.length = GST_BUFFER_MAXSIZE(outbuf);
- xframe.mvs = NULL;
- xframe.colorspace = divxenc->csp;
+ xframe.produce_empty_frame = 0;
if ((ret = encore(divxenc->handle, ENC_OPT_ENCODE,
&xframe, &xres))) {
gst_element_error(GST_ELEMENT(divxenc),
- "Error encoding divx frame: %d\n", ret);
+ "Error encoding divx frame: %s (%d)",
+ gst_divxenc_error(ret), ret);
gst_buffer_unref(buf);
return;
}
GST_BUFFER_SIZE(outbuf) = xframe.length;
- if (xres.is_key_frame)
+ if (xres.cType == 'I')
GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_KEY_UNIT);
/* go out, multiply! */
divxenc = GST_DIVXENC(gst_pad_get_parent (pad));
/* if there's something old around, remove it */
- if (divxenc->handle) {
- gst_divxenc_unset(divxenc);
- }
+ gst_divxenc_unset(divxenc);
/* we are not going to act on variable caps */
if (!GST_CAPS_IS_FIXED(vscaps))
for (caps = vscaps; caps != NULL; caps = caps->next) {
int w,h,d;
guint32 fourcc;
- gint divx_cs;
+ guint32 divx_cs;
+ gint bitcnt = 0;
gst_caps_get_int(caps, "width", &w);
gst_caps_get_int(caps, "height", &h);
gst_caps_get_fourcc_int(caps, "format", &fourcc);
switch (fourcc) {
case GST_MAKE_FOURCC('I','4','2','0'):
case GST_MAKE_FOURCC('I','Y','U','V'):
- divx_cs = ENC_CSP_I420;
+ divx_cs = GST_MAKE_FOURCC('I','4','2','0');
break;
case GST_MAKE_FOURCC('Y','U','Y','2'):
- divx_cs = ENC_CSP_YUY2;
+ case GST_MAKE_FOURCC('Y','U','Y','V'):
+ divx_cs = GST_MAKE_FOURCC('Y','U','Y','2');
break;
case GST_MAKE_FOURCC('Y','V','1','2'):
- divx_cs = ENC_CSP_YV12;
+ divx_cs = GST_MAKE_FOURCC('Y','V','1','2');
+ break;
+ case GST_MAKE_FOURCC('Y','V','Y','U'):
+ divx_cs = GST_MAKE_FOURCC('Y','V','Y','U');
break;
case GST_MAKE_FOURCC('U','Y','V','Y'):
- divx_cs = ENC_CSP_UYVY;
+ divx_cs = GST_MAKE_FOURCC('U','Y','V','Y');
break;
case GST_MAKE_FOURCC('R','G','B',' '):
gst_caps_get_int(caps, "depth", &d);
switch (d) {
case 24:
- divx_cs = ENC_CSP_RGB24;
+ divx_cs = 0;
+ bitcnt = 24;
break;
case 32:
- divx_cs = ENC_CSP_RGB32;
+ divx_cs = 0;
+ bitcnt = 32;
break;
default:
goto trynext;
* linking, so we accept here, get the fps on
* the first cycle and set it all up then */
divxenc->csp = divx_cs;
+ divxenc->bitcnt = bitcnt;
divxenc->width = w;
divxenc->height = h;
return gst_pad_try_set_caps(divxenc->srcpad,
case ARG_BITRATE:
divxenc->bitrate = g_value_get_ulong(value);
break;
- case ARG_BUFSIZE:
- divxenc->buffer_size = g_value_get_ulong(value);
- break;
case ARG_MAXKEYINTERVAL:
divxenc->max_key_interval = g_value_get_int(value);
break;
+ case ARG_QUALITY:
+ divxenc->quality = g_value_get_int(value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case ARG_MAXKEYINTERVAL:
g_value_set_int(value, divxenc->max_key_interval);
break;
+ case ARG_QUALITY:
+ g_value_set_int(value, divxenc->quality);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
GstPlugin *plugin)
{
GstElementFactory *factory;
+ int lib_version;
+
+ lib_version = encore(NULL, ENC_OPT_VERSION, 0, 0);
+ if (lib_version != ENCORE_VERSION) {
+ g_warning("Version mismatch! This plugin was compiled for "
+ "DivX version %d, while your library has version %d!",
+ ENCORE_VERSION, lib_version);
+ return FALSE;
+ }
if (!gst_library_load("gstvideo"))
return FALSE;
/* max key interval */
gint max_key_interval;
+ /* amount of motion estimation to do */
+ gint quality;
+
/* divx handle */
void *handle;
- int csp;
- int width, height;
+ guint32 csp;
+ gint bitcnt;
+ gint width, height;
};
struct _GstDivxEncClass {