mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-23 14:36:24 +00:00
drop mpeg2dec 0.2.1 support in favor of 0.3.0.
Original commit message from CVS: drop mpeg2dec 0.2.1 support in favor of 0.3.0. keeping old code around in cvs for a while just in case someone needs it.
This commit is contained in:
parent
976447564e
commit
4af44b1075
7 changed files with 843 additions and 920 deletions
19
configure.ac
19
configure.ac
|
@ -690,7 +690,24 @@ GST_CHECK_FEATURE(MJPEGTOOLS, [mjpegtools], jpegmmxenc jpegmmxdec, [
|
|||
dnl *** mpeg2dec ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_MPEG2DEC, true)
|
||||
GST_CHECK_FEATURE(MPEG2DEC, [mpeg2dec], mpeg2dec, [
|
||||
AC_CHECK_MPEG2DEC(HAVE_MPEG2DEC=yes, HAVE_MPEG2DEC=no)
|
||||
PKG_CHECK_MODULES(LIBMPEG2, libmpeg2 >= 0.3.0,
|
||||
HAVE_LIBMPEG2="yes", HAVE_LIBMPEG2="no")
|
||||
AC_SUBST(LIBMPEG2_CFLAGS)
|
||||
AC_SUBST(LIBMPEG2_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(LIBCPUACCEL, libcpuaccel >= 0.3.0,
|
||||
HAVE_LIBCPUACCEL="yes", HAVE_LIBCPUACCEL="no")
|
||||
AC_SUBST(LIBCPUACCEL_CFLAGS)
|
||||
AC_SUBST(LIBCPUACCEL_LIBS)
|
||||
|
||||
HAVE_MPEG2DEC="no"
|
||||
if test x$HAVE_LIBMPEG2 = xyes -a x$HAVE_LIBCPUACCEL = xyes; then
|
||||
HAVE_MPEG2DEC="yes"
|
||||
MPEG2DEC_CFLAGS="$LIBMPEG2_CFLAGS $LIBCPUACCEL_CFLAGS"
|
||||
MPEG2DEC_LIBS="$LIBMPEG2_LIBS $LIBCPUACCEL_LIBS"
|
||||
AC_SUBST(MPEG2DEC_CFLAGS)
|
||||
AC_SUBST(MPEG2DEC_LIBS)
|
||||
fi
|
||||
])
|
||||
|
||||
dnl *** openquicktime ***
|
||||
|
|
|
@ -3,7 +3,7 @@ plugindir = $(libdir)/gst
|
|||
plugin_LTLIBRARIES = libgstmpeg2dec.la
|
||||
|
||||
libgstmpeg2dec_la_SOURCES = gstmpeg2dec.c
|
||||
libgstmpeg2dec_la_CFLAGS = $(GST_CFLAGS) $(MPEG2DEC_CFLAGS) $(FOMIT_FRAME_POINTER) -ffast-math
|
||||
libgstmpeg2dec_la_CFLAGS = $(GST_CFLAGS) $(MPEG2DEC_CFLAGS)
|
||||
libgstmpeg2dec_la_LIBADD = $(MPEG2DEC_LIBS)
|
||||
libgstmpeg2dec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#include <mpeg2dec/mm_accel.h>
|
||||
#include "gstmpeg2deccvs.h"
|
||||
#include <mpeg2dec/video_out.h>
|
||||
#include "gstmpeg2dec.h"
|
||||
|
||||
/* elementfactory information */
|
||||
static GstElementDetails gst_mpeg2dec_details = {
|
||||
|
@ -31,8 +32,8 @@ static GstElementDetails gst_mpeg2dec_details = {
|
|||
"GPL",
|
||||
"Uses libmpeg2 to decode MPEG video streams",
|
||||
VERSION,
|
||||
"Wim Taymans <wim.taymans@chello.be>, "
|
||||
"(C) 2002",
|
||||
"David I. Lehn <dlehn@users.sourceforge.net>",
|
||||
"(C) 2000",
|
||||
};
|
||||
|
||||
/* Mpeg2dec signals and args */
|
||||
|
@ -47,27 +48,36 @@ enum {
|
|||
/* FILL ME */
|
||||
};
|
||||
|
||||
static double video_rates[16] =
|
||||
{
|
||||
0.0,
|
||||
24000.0/1001.,
|
||||
24.0,
|
||||
25.0,
|
||||
30000.0/1001.,
|
||||
30.0,
|
||||
50.0,
|
||||
60000.0/1001.,
|
||||
60.0,
|
||||
1.0,
|
||||
5.0,
|
||||
10.0,
|
||||
12.0,
|
||||
15.0,
|
||||
0.0,
|
||||
0.0
|
||||
};
|
||||
|
||||
GST_PAD_TEMPLATE_FACTORY (src_template_factory,
|
||||
"src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_CAPS_NEW (
|
||||
"mpeg2dec_src",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y','V','1','2')),
|
||||
"width", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"height", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"pixel_width", GST_PROPS_INT_RANGE (1, 255),
|
||||
"pixel_height", GST_PROPS_INT_RANGE (1, 255)
|
||||
),
|
||||
GST_CAPS_NEW (
|
||||
"mpeg2dec_src",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')),
|
||||
"width", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"height", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"pixel_width", GST_PROPS_INT_RANGE (1, 255),
|
||||
"pixel_height", GST_PROPS_INT_RANGE (1, 255)
|
||||
"height", GST_PROPS_INT_RANGE (16, 4096)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -92,21 +102,11 @@ static void gst_mpeg2dec_set_property (GObject *object, guint prop_id,
|
|||
const GValue *value, GParamSpec *pspec);
|
||||
static void gst_mpeg2dec_get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec);
|
||||
static void gst_mpeg2dec_set_cache (GstElement *element, GstCache *cache);
|
||||
static GstCache* gst_mpeg2dec_get_cache (GstElement *element);
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_src_formats (GstPad *pad);
|
||||
static const GstEventMask*
|
||||
gst_mpeg2dec_get_src_event_masks (GstPad *pad);
|
||||
static gboolean gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event);
|
||||
static const GstPadQueryType*
|
||||
gst_mpeg2dec_get_src_query_types (GstPad *pad);
|
||||
static gboolean gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
||||
GstFormat *format, gint64 *value);
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_sink_formats (GstPad *pad);
|
||||
static gboolean gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
GstFormat *dest_format, gint64 *dest_value);
|
||||
static gboolean gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
|
@ -162,8 +162,237 @@ gst_mpeg2dec_class_init(GstMpeg2decClass *klass)
|
|||
gobject_class->dispose = gst_mpeg2dec_dispose;
|
||||
|
||||
gstelement_class->change_state = gst_mpeg2dec_change_state;
|
||||
gstelement_class->set_cache = gst_mpeg2dec_set_cache;
|
||||
gstelement_class->get_cache = gst_mpeg2dec_get_cache;
|
||||
}
|
||||
|
||||
typedef struct gst_mpeg2dec_vo_frame_s {
|
||||
vo_frame_t vo;
|
||||
|
||||
GstBuffer *buffer;
|
||||
gboolean sent;
|
||||
} gst_mpeg2dec_vo_frame_t;
|
||||
|
||||
#define NUM_FRAMES 3
|
||||
|
||||
typedef struct gst_mpeg2dec_vo_instance_s {
|
||||
vo_instance_t vo;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
gint prediction_index;
|
||||
gst_mpeg2dec_vo_frame_t frames[NUM_FRAMES];
|
||||
} gst_mpeg2dec_vo_instance_t;
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_frame_draw (vo_frame_t * frame)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t *_instance;
|
||||
gst_mpeg2dec_vo_frame_t *_frame;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
gint64 pts = -1;
|
||||
|
||||
g_return_if_fail (frame != NULL);
|
||||
g_return_if_fail (((gst_mpeg2dec_vo_frame_t *)frame)->buffer != NULL);
|
||||
|
||||
_frame = (gst_mpeg2dec_vo_frame_t *)frame;
|
||||
_instance = (gst_mpeg2dec_vo_instance_t *)frame->instance;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (_instance->mpeg2dec);
|
||||
|
||||
|
||||
/* we have to be carefull here. we do mpeg2_close in the READY state
|
||||
* but it can send a few frames still. We have to make sure we are playing
|
||||
* when we send frames. we do have to free those last frames though */
|
||||
if (GST_STATE (GST_ELEMENT (mpeg2dec)) != GST_STATE_PLAYING) {
|
||||
gst_buffer_unref (_frame->buffer);
|
||||
/* pretend we have sent the frame */
|
||||
_frame->sent = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mpeg2dec->frame_rate_code != mpeg2dec->decoder->frame_rate_code)
|
||||
{
|
||||
mpeg2dec->frame_rate_code = mpeg2dec->decoder->frame_rate_code;
|
||||
|
||||
g_object_notify (G_OBJECT (mpeg2dec), "frame_rate");
|
||||
}
|
||||
|
||||
pts = mpeg2dec->next_time - 3 * (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (_frame->buffer) = pts;
|
||||
|
||||
GST_DEBUG (0, "out: %lld %d %lld", GST_BUFFER_TIMESTAMP (_frame->buffer),
|
||||
mpeg2dec->decoder->frame_rate_code,
|
||||
(long long)(GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]));
|
||||
|
||||
mpeg2dec->next_time += (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]) + mpeg2dec->adjust;
|
||||
|
||||
GST_BUFFER_FLAG_SET (_frame->buffer, GST_BUFFER_READONLY);
|
||||
mpeg2dec->frames_per_PTS++;
|
||||
mpeg2dec->first = FALSE;
|
||||
_frame->sent = TRUE;
|
||||
mpeg2dec->total_frames++;
|
||||
gst_pad_push (mpeg2dec->srcpad, _frame->buffer);
|
||||
}
|
||||
|
||||
static int
|
||||
gst_mpeg2dec_vo_setup (vo_instance_t * instance, int width, int height)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * _instance;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
|
||||
g_return_val_if_fail (instance != NULL, -1);
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: setup w=%d h=%d", width, height);
|
||||
|
||||
_instance = (gst_mpeg2dec_vo_instance_t*)instance;
|
||||
mpeg2dec = _instance->mpeg2dec;
|
||||
_instance->prediction_index = 1;
|
||||
mpeg2dec->width = width;
|
||||
mpeg2dec->height = height;
|
||||
mpeg2dec->total_frames = 0;
|
||||
|
||||
gst_pad_try_set_caps (mpeg2dec->srcpad,
|
||||
gst_caps_new (
|
||||
"mpeg2dec_caps",
|
||||
"video/raw",
|
||||
gst_props_new (
|
||||
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')),
|
||||
"width", GST_PROPS_INT (width),
|
||||
"height", GST_PROPS_INT (height),
|
||||
NULL)));
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_close (vo_instance_t * instance)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * _instance;
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: close");
|
||||
|
||||
_instance = (gst_mpeg2dec_vo_instance_t*)instance;
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static vo_frame_t *
|
||||
gst_mpeg2dec_vo_get_frame (vo_instance_t * instance, int flags)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * _instance;
|
||||
gst_mpeg2dec_vo_frame_t *frame;
|
||||
size_t size0;
|
||||
uint8_t *data = NULL;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
|
||||
g_return_val_if_fail (instance != NULL, NULL);
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: get_frame");
|
||||
|
||||
_instance = (gst_mpeg2dec_vo_instance_t *)instance;
|
||||
|
||||
mpeg2dec = _instance->mpeg2dec;
|
||||
|
||||
if (flags & VO_PREDICTION_FLAG) {
|
||||
_instance->prediction_index ^= 1;
|
||||
frame = &_instance->frames[_instance->prediction_index];
|
||||
} else {
|
||||
frame = &_instance->frames[2];
|
||||
}
|
||||
|
||||
/* we are reusing this frame */
|
||||
if (frame->buffer != NULL) {
|
||||
/* if the frame wasn't sent, we have to unref twice */
|
||||
if (!frame->sent)
|
||||
gst_buffer_unref (frame->buffer);
|
||||
gst_buffer_unref (frame->buffer);
|
||||
frame->buffer = NULL;
|
||||
}
|
||||
|
||||
size0 = mpeg2dec->width * mpeg2dec->height / 4;
|
||||
|
||||
if (mpeg2dec->peerpool) {
|
||||
frame->buffer = gst_buffer_new_from_pool (mpeg2dec->peerpool, 0, 0);
|
||||
} else {
|
||||
size_t size = 6 * size0;
|
||||
size_t offset;
|
||||
GstBuffer *parent;
|
||||
|
||||
parent = gst_buffer_new ();
|
||||
|
||||
GST_BUFFER_SIZE(parent) = size + 0x10;
|
||||
GST_BUFFER_DATA(parent) = data = g_new(uint8_t, size + 0x10);
|
||||
|
||||
offset = 0x10 - (((unsigned long)data) & 0xf);
|
||||
frame->buffer = gst_buffer_create_sub(parent, offset, size);
|
||||
|
||||
gst_buffer_unref(parent);
|
||||
}
|
||||
data = GST_BUFFER_DATA(frame->buffer);
|
||||
|
||||
/* need ref=2 */
|
||||
/* 1 - unref when reusing this frame */
|
||||
/* 2 - unref when other elements done with buffer */
|
||||
gst_buffer_ref (frame->buffer);
|
||||
|
||||
frame->vo.base[0] = data;
|
||||
frame->vo.base[1] = data + 4 * size0;
|
||||
frame->vo.base[2] = data + 5 * size0;
|
||||
/*printf("base[0]=%p\n", frame->vo.base[0]); */
|
||||
frame->sent = FALSE;
|
||||
|
||||
return (vo_frame_t *)frame;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_open (GstMpeg2dec *mpeg2dec)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * instance;
|
||||
gint i,j;
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: open");
|
||||
|
||||
instance = g_new (gst_mpeg2dec_vo_instance_t, 1);
|
||||
|
||||
instance->vo.setup = gst_mpeg2dec_vo_setup;
|
||||
instance->vo.close = gst_mpeg2dec_vo_close;
|
||||
instance->vo.get_frame = gst_mpeg2dec_vo_get_frame;
|
||||
instance->mpeg2dec = mpeg2dec;
|
||||
|
||||
for (i=0; i<NUM_FRAMES; i++) {
|
||||
for (j=0; j<3; j++) {
|
||||
instance->frames[j].vo.base[j] = NULL;
|
||||
}
|
||||
instance->frames[i].vo.copy = NULL;
|
||||
instance->frames[i].vo.field = NULL;
|
||||
instance->frames[i].vo.draw = gst_mpeg2dec_vo_frame_draw;
|
||||
instance->frames[i].vo.instance = (vo_instance_t *)instance;
|
||||
instance->frames[i].buffer = NULL;
|
||||
}
|
||||
|
||||
mpeg2dec->vo = (vo_instance_t *) instance;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_destroy (GstMpeg2dec *mpeg2dec)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * instance;
|
||||
gint i;
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: destroy");
|
||||
|
||||
instance = (gst_mpeg2dec_vo_instance_t *) mpeg2dec->vo;
|
||||
|
||||
for (i=0; i<NUM_FRAMES; i++) {
|
||||
if (instance->frames[i].buffer) {
|
||||
if (!instance->frames[i].sent) {
|
||||
gst_buffer_unref (instance->frames[i].buffer);
|
||||
}
|
||||
gst_buffer_unref (instance->frames[i].buffer);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (instance);
|
||||
mpeg2dec->vo = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -173,22 +402,20 @@ gst_mpeg2dec_init (GstMpeg2dec *mpeg2dec)
|
|||
mpeg2dec->sinkpad = gst_pad_new_from_template (
|
||||
GST_PAD_TEMPLATE_GET (sink_template_factory), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->sinkpad);
|
||||
gst_pad_set_chain_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_chain));
|
||||
gst_pad_set_formats_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_sink_formats));
|
||||
gst_pad_set_convert_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_convert_sink));
|
||||
gst_pad_set_chain_function (mpeg2dec->sinkpad, gst_mpeg2dec_chain);
|
||||
gst_pad_set_convert_function (mpeg2dec->sinkpad, gst_mpeg2dec_convert_sink);
|
||||
|
||||
mpeg2dec->srcpad = gst_pad_new_from_template (
|
||||
GST_PAD_TEMPLATE_GET (src_template_factory), "src");
|
||||
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->srcpad);
|
||||
gst_pad_set_formats_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_formats));
|
||||
gst_pad_set_event_mask_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_event_masks));
|
||||
gst_pad_set_event_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_event));
|
||||
gst_pad_set_query_type_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_query_types));
|
||||
gst_pad_set_query_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_query));
|
||||
gst_pad_set_convert_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_convert_src));
|
||||
gst_pad_set_convert_function (mpeg2dec->srcpad, gst_mpeg2dec_convert_src);
|
||||
|
||||
/* initialize the mpeg2dec decoder state */
|
||||
mpeg2dec->decoder = mpeg2_init (mm_accel());
|
||||
mpeg2dec->decoder = g_new (mpeg2dec_t, 1);
|
||||
mpeg2dec->decoder->frame_rate_code = 0;
|
||||
mpeg2dec->accel = mm_accel();
|
||||
|
||||
GST_FLAG_SET (GST_ELEMENT (mpeg2dec), GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
@ -198,140 +425,21 @@ gst_mpeg2dec_dispose (GObject *object)
|
|||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
|
||||
|
||||
if (!mpeg2dec->closed)
|
||||
mpeg2_close (mpeg2dec->decoder);
|
||||
g_free (mpeg2dec->decoder);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_set_cache (GstElement *element, GstCache *cache)
|
||||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
|
||||
|
||||
mpeg2dec->cache = cache;
|
||||
|
||||
gst_cache_get_writer_id (cache, GST_OBJECT (element), &mpeg2dec->cache_id);
|
||||
}
|
||||
|
||||
static GstCache*
|
||||
gst_mpeg2dec_get_cache (GstElement *element)
|
||||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
|
||||
|
||||
return mpeg2dec->cache;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_alloc_buffer (GstMpeg2dec *mpeg2dec, const mpeg2_info_t *info)
|
||||
{
|
||||
GstBuffer *outbuf = NULL;
|
||||
gint size = mpeg2dec->width * mpeg2dec->height;
|
||||
guint8 *buf[3], *out;
|
||||
const picture_t *picture;
|
||||
|
||||
if (mpeg2dec->peerpool) {
|
||||
outbuf = gst_buffer_new_from_pool (mpeg2dec->peerpool, 0, 0);
|
||||
}
|
||||
if (!outbuf) {
|
||||
outbuf = gst_buffer_new_and_alloc ((size * 3) / 2);
|
||||
}
|
||||
|
||||
out = GST_BUFFER_DATA (outbuf);
|
||||
|
||||
buf[0] = out;
|
||||
if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) {
|
||||
buf[1] = buf[0] + size;
|
||||
buf[2] = buf[1] + size/4;
|
||||
}
|
||||
else {
|
||||
buf[2] = buf[0] + size;
|
||||
buf[1] = buf[2] + size/4;
|
||||
}
|
||||
|
||||
gst_buffer_ref (outbuf);
|
||||
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
|
||||
|
||||
picture = info->current_picture;
|
||||
|
||||
if (picture && (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I)
|
||||
{
|
||||
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
|
||||
}
|
||||
else {
|
||||
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_KEY_UNIT);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_negotiate_format (GstMpeg2dec *mpeg2dec)
|
||||
{
|
||||
GstCaps *allowed;
|
||||
GstCaps *trylist;
|
||||
|
||||
/* we what we are allowed to do */
|
||||
allowed = gst_pad_get_allowed_caps (mpeg2dec->srcpad);
|
||||
/* we could not get allowed caps */
|
||||
if (!allowed) {
|
||||
allowed = GST_CAPS_NEW (
|
||||
"mpeg2dec_negotiate",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
|
||||
);
|
||||
}
|
||||
|
||||
/* try to fix our height */
|
||||
trylist = gst_caps_intersect (allowed,
|
||||
GST_CAPS_NEW (
|
||||
"mpeg2dec_negotiate",
|
||||
"video/raw",
|
||||
"width", GST_PROPS_INT (mpeg2dec->width),
|
||||
"height", GST_PROPS_INT (mpeg2dec->height),
|
||||
"pixel_width", GST_PROPS_INT (mpeg2dec->pixel_width),
|
||||
"pixel_height", GST_PROPS_INT (mpeg2dec->pixel_height)
|
||||
));
|
||||
/* prepare for looping */
|
||||
trylist = gst_caps_normalize (trylist);
|
||||
|
||||
while (trylist) {
|
||||
GstCaps *to_try = gst_caps_copy_1 (trylist);
|
||||
|
||||
/* try each format */
|
||||
if (gst_pad_try_set_caps (mpeg2dec->srcpad, to_try) > 0) {
|
||||
guint32 fourcc;
|
||||
|
||||
/* it worked, try to find what it was again */
|
||||
gst_caps_get_fourcc_int (to_try, "format", &fourcc);
|
||||
|
||||
if (fourcc == GST_STR_FOURCC ("I420")) {
|
||||
mpeg2dec->format = MPEG2DEC_FORMAT_I420;
|
||||
}
|
||||
else {
|
||||
mpeg2dec->format = MPEG2DEC_FORMAT_YV12;
|
||||
}
|
||||
break;
|
||||
}
|
||||
trylist = trylist->next;
|
||||
}
|
||||
/* oops list exhausted and nothing was found... */
|
||||
if (!trylist) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_chain (GstPad *pad, GstBuffer *buf)
|
||||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
guint32 size;
|
||||
guint8 *data, *end;
|
||||
guchar *data;
|
||||
guint num_frames;
|
||||
gint64 pts;
|
||||
const mpeg2_info_t *info;
|
||||
gint state;
|
||||
gboolean done = FALSE;
|
||||
|
||||
GST_DEBUG (0, "MPEG2DEC: chain called");
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
@ -341,16 +449,18 @@ gst_mpeg2dec_chain (GstPad *pad, GstBuffer *buf)
|
|||
{
|
||||
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
//mpeg2dec->decoder->is_sequence_needed = 1;
|
||||
GST_DEBUG (GST_CAT_EVENT, "discont\n");
|
||||
GST_DEBUG (GST_CAT_EVENT, "mpeg2dec: discont\n");
|
||||
mpeg2dec->first = TRUE;
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
mpeg2dec->last_PTS = -1;
|
||||
mpeg2dec->adjust = 0;
|
||||
mpeg2dec->next_time = 0;
|
||||
mpeg2dec->discont_pending = TRUE;
|
||||
gst_pad_event_default (pad, event);
|
||||
return;
|
||||
}
|
||||
case GST_EVENT_EOS:
|
||||
if (!mpeg2dec->closed) {
|
||||
/* close flushes the last few frames */
|
||||
mpeg2_close (mpeg2dec->decoder);
|
||||
mpeg2dec->closed = TRUE;
|
||||
}
|
||||
|
@ -363,187 +473,74 @@ gst_mpeg2dec_chain (GstPad *pad, GstBuffer *buf)
|
|||
size = GST_BUFFER_SIZE (buf);
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
pts = GST_BUFFER_TIMESTAMP (buf);
|
||||
/* rationale for these heuristics;
|
||||
* - we keep our own timestamp guestimate in next_time, this is based on the
|
||||
* frame rate of the video stream.
|
||||
* - we receive PTS values in the buffer timestamp.
|
||||
* - we only accept new pts values if they are monotonically increasing.
|
||||
* - if we have more than 10 frames without a new PTS value, we compare our
|
||||
* internal counter to the PTS and calculate a diff. This is usefull when the
|
||||
* framerate in the stream is wrong.
|
||||
* - if the PTS and our own counter are adrift bu more than 10 frames, we assume
|
||||
* a discontinuity in the PTS and adjust our own counter.
|
||||
*/
|
||||
GST_DEBUG (GST_CAT_CLOCK, "mpeg2dec: pts %llu\n", pts);
|
||||
if (!mpeg2dec->first) {
|
||||
if (mpeg2dec->last_PTS < pts) {
|
||||
|
||||
info = mpeg2_info (mpeg2dec->decoder);
|
||||
end = data + size;
|
||||
if (pts != mpeg2dec->next_time && mpeg2dec->frames_per_PTS > 10) {
|
||||
gint64 diff = ABS (pts - mpeg2dec->last_PTS);
|
||||
|
||||
if (pts != -1) {
|
||||
gint64 mpeg_pts = GSTTIME_TO_MPEGTIME (pts);
|
||||
|
||||
GST_DEBUG (0, "have pts: %lld (%lld)",
|
||||
mpeg_pts, MPEGTIME_TO_GSTTIME (mpeg_pts));
|
||||
|
||||
mpeg2_pts (mpeg2dec->decoder, mpeg_pts);
|
||||
if (diff > (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]) + GST_SECOND/1000) {
|
||||
mpeg2dec->adjust = (diff / mpeg2dec->frames_per_PTS +1) -
|
||||
(GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]);
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (GST_CAT_CLOCK, "no pts");
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
|
||||
mpeg2_buffer (mpeg2dec->decoder, data, end);
|
||||
|
||||
while (!done) {
|
||||
state = mpeg2_parse (mpeg2dec->decoder);
|
||||
switch (state) {
|
||||
case STATE_SEQUENCE:
|
||||
{
|
||||
mpeg2dec->width = info->sequence->width;
|
||||
mpeg2dec->height = info->sequence->height;
|
||||
mpeg2dec->pixel_width = info->sequence->pixel_width;
|
||||
mpeg2dec->pixel_height = info->sequence->pixel_height;
|
||||
mpeg2dec->total_frames = 0;
|
||||
mpeg2dec->frame_period = info->sequence->frame_period * GST_USECOND / 27;
|
||||
|
||||
GST_DEBUG (0, "sequence flags: %d, frame period: %d",
|
||||
info->sequence->flags, info->sequence->frame_period);
|
||||
|
||||
if (!gst_mpeg2dec_negotiate_format (mpeg2dec)) {
|
||||
gst_element_error (GST_ELEMENT (mpeg2dec), "could not negotiate format");
|
||||
return;
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
}
|
||||
if (ABS (pts - mpeg2dec->last_PTS) > (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code])*10) {
|
||||
|
||||
gst_mpeg2dec_alloc_buffer (mpeg2dec, info);
|
||||
break;
|
||||
}
|
||||
case STATE_SEQUENCE_REPEATED:
|
||||
GST_DEBUG (0, "sequence repeated");
|
||||
break;
|
||||
case STATE_GOP:
|
||||
break;
|
||||
case STATE_PICTURE:
|
||||
{
|
||||
gboolean key_frame = FALSE;
|
||||
|
||||
|
||||
if (info->current_picture)
|
||||
key_frame = (info->current_picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
|
||||
|
||||
gst_mpeg2dec_alloc_buffer (mpeg2dec, info);
|
||||
|
||||
if (key_frame && mpeg2dec->discont_pending) {
|
||||
mpeg2dec->discont_pending = FALSE;
|
||||
mpeg2dec->first = TRUE;
|
||||
if (pts != -1 && mpeg2dec->last_PTS == -1) {
|
||||
mpeg2dec->last_PTS = pts;
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
}
|
||||
|
||||
if (mpeg2dec->cache && pts != GST_CLOCK_TIME_NONE) {
|
||||
gst_cache_add_association (mpeg2dec->cache, mpeg2dec->cache_id,
|
||||
(key_frame ? GST_ACCOCIATION_FLAG_KEY_UNIT : 0),
|
||||
GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buf),
|
||||
GST_FORMAT_TIME, pts, 0);
|
||||
if (mpeg2dec->next_time < pts) {
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_SLICE_1ST:
|
||||
GST_DEBUG (0, "slice 1st");
|
||||
break;
|
||||
case STATE_PICTURE_2ND:
|
||||
GST_DEBUG (0, "picture second\n");
|
||||
break;
|
||||
case STATE_SLICE:
|
||||
case STATE_END:
|
||||
{
|
||||
GstBuffer *outbuf = NULL;
|
||||
|
||||
if (info->display_fbuf && info->display_fbuf->id) {
|
||||
const picture_t *picture;
|
||||
|
||||
outbuf = (GstBuffer *) info->display_fbuf->id;
|
||||
picture = info->display_picture;
|
||||
|
||||
if (picture->flags & PIC_FLAG_PTS) {
|
||||
GstClockTime time = MPEGTIME_TO_GSTTIME (picture->pts);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = time;
|
||||
|
||||
mpeg2dec->next_time = time;
|
||||
}
|
||||
else {
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = mpeg2dec->next_time;
|
||||
}
|
||||
mpeg2dec->next_time += (mpeg2dec->frame_period * picture->nb_fields) >> 1;
|
||||
|
||||
GST_DEBUG (0, "picture: %s %s fields:%d ts:%lld",
|
||||
(picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff " : " "),
|
||||
(picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "),
|
||||
picture->nb_fields,
|
||||
GST_BUFFER_TIMESTAMP (outbuf));
|
||||
|
||||
/*
|
||||
if (picture->flags & PIC_FLAG_SKIP ||
|
||||
mpeg2dec->discont_pending ||
|
||||
(mpeg2dec->first && !GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_KEY_UNIT)))
|
||||
{
|
||||
if (mpeg2dec->last_PTS < pts) {
|
||||
mpeg2dec->next_time = pts;
|
||||
g_print ("** adjust next_time %lld %lld\n", mpeg2dec->last_PTS, pts);
|
||||
}
|
||||
*/
|
||||
if (picture->flags & PIC_FLAG_SKIP ||
|
||||
!GST_PAD_IS_USABLE (mpeg2dec->srcpad)) {
|
||||
gst_buffer_unref (outbuf);
|
||||
}
|
||||
else {
|
||||
mpeg2dec->first = FALSE;
|
||||
gst_pad_push (mpeg2dec->srcpad, outbuf);
|
||||
}
|
||||
}
|
||||
if (info->discard_fbuf && info->discard_fbuf->id) {
|
||||
gst_buffer_unref ((GstBuffer *)info->discard_fbuf->id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/* need more data */
|
||||
case -1:
|
||||
done = TRUE;
|
||||
break;
|
||||
/* error */
|
||||
case STATE_INVALID:
|
||||
gst_element_error (GST_ELEMENT (mpeg2dec), "fatal error");
|
||||
done = TRUE;
|
||||
break;
|
||||
default:
|
||||
g_warning ("%s: unhandled state %d, FIXME",
|
||||
gst_element_get_name (GST_ELEMENT (mpeg2dec)),
|
||||
state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mpeg2dec->last_PTS = pts;
|
||||
|
||||
|
||||
/* fprintf(stderr, "MPEG2DEC: in timestamp=%llu\n",GST_BUFFER_TIMESTAMP(buf)); */
|
||||
/* fprintf(stderr, "MPEG2DEC: have buffer of %d bytes\n",size); */
|
||||
num_frames = mpeg2_decode_data(mpeg2dec->decoder, data, data + size);
|
||||
/*fprintf(stderr, "MPEG2DEC: decoded %d frames\n", num_frames);*/
|
||||
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_sink_formats (GstPad *pad)
|
||||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_BYTES,
|
||||
GST_FORMAT_TIME,
|
||||
0
|
||||
};
|
||||
return formats;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
GstFormat *dest_format, gint64 *dest_value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
const mpeg2_info_t *info;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
info = mpeg2_info (mpeg2dec->decoder);
|
||||
|
||||
switch (src_format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
switch (*dest_format) {
|
||||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_TIME;
|
||||
case GST_FORMAT_TIME:
|
||||
if (info->sequence && info->sequence->byte_rate) {
|
||||
*dest_value = GST_SECOND * src_value / info->sequence->byte_rate;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
@ -553,10 +550,6 @@ gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_BYTES;
|
||||
case GST_FORMAT_BYTES:
|
||||
if (info->sequence && info->sequence->byte_rate) {
|
||||
*dest_value = src_value * info->sequence->byte_rate / GST_SECOND;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
@ -567,31 +560,15 @@ gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
return res;
|
||||
}
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_src_formats (GstPad *pad)
|
||||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_BYTES,
|
||||
GST_FORMAT_TIME,
|
||||
GST_FORMAT_UNITS,
|
||||
0
|
||||
};
|
||||
return formats;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
GstFormat *dest_format, gint64 *dest_value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
const mpeg2_info_t *info;
|
||||
guint64 scale = 1;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
info = mpeg2_info (mpeg2dec->decoder);
|
||||
|
||||
switch (src_format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
switch (*dest_format) {
|
||||
|
@ -607,12 +584,12 @@ gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_BYTES;
|
||||
case GST_FORMAT_BYTES:
|
||||
scale = 6 * (mpeg2dec->width * mpeg2dec->height >> 2);
|
||||
case GST_FORMAT_UNITS:
|
||||
if (info->sequence && mpeg2dec->frame_period) {
|
||||
*dest_value = src_value * scale / mpeg2dec->frame_period;
|
||||
*dest_value = src_value * 6 * (mpeg2dec->width * mpeg2dec->height >> 2) *
|
||||
video_rates[mpeg2dec->decoder->frame_rate_code] / GST_SECOND;
|
||||
break;
|
||||
case GST_FORMAT_UNITS:
|
||||
*dest_value = src_value * video_rates[mpeg2dec->decoder->frame_rate_code] / GST_SECOND;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
@ -622,10 +599,18 @@ gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_TIME;
|
||||
case GST_FORMAT_TIME:
|
||||
*dest_value = src_value * mpeg2dec->frame_period;
|
||||
if (video_rates[mpeg2dec->decoder->frame_rate_code] != 0.0) {
|
||||
*dest_value = src_value * GST_SECOND /
|
||||
video_rates[mpeg2dec->decoder->frame_rate_code];
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
break;
|
||||
case GST_FORMAT_BYTES:
|
||||
*dest_value = src_value * 6 * ((mpeg2dec->width * mpeg2dec->height) >> 2);
|
||||
*dest_value = src_value * 6 * (mpeg2dec->width * mpeg2dec->height >> 2);
|
||||
break;
|
||||
case GST_FORMAT_UNITS:
|
||||
*dest_value = src_value;
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
|
@ -637,24 +622,15 @@ gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
return res;
|
||||
}
|
||||
|
||||
static const GstPadQueryType*
|
||||
gst_mpeg2dec_get_src_query_types (GstPad *pad)
|
||||
{
|
||||
static const GstPadQueryType types[] = {
|
||||
GST_PAD_QUERY_TOTAL,
|
||||
GST_PAD_QUERY_POSITION,
|
||||
0
|
||||
};
|
||||
return types;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
||||
GstFormat *format, gint64 *value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
static const GstFormat *formats;
|
||||
static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_BYTES };
|
||||
#define MAX_SEEK_FORMATS 1 /* we can only do time seeking for now */
|
||||
gint i;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
|
@ -671,15 +647,11 @@ gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
|||
{
|
||||
res = FALSE;
|
||||
|
||||
/* get our peer formats */
|
||||
formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
|
||||
|
||||
/* while we did not exhaust our seek formats without result */
|
||||
while (formats && *formats) {
|
||||
for (i = 0; i < MAX_SEEK_FORMATS && !res; i++) {
|
||||
GstFormat peer_format;
|
||||
gint64 peer_value;
|
||||
|
||||
peer_format = *formats;
|
||||
peer_format = formats[i];
|
||||
|
||||
/* do the probe */
|
||||
if (gst_pad_query (GST_PAD_PEER (mpeg2dec->sinkpad), GST_PAD_QUERY_TOTAL,
|
||||
|
@ -697,7 +669,6 @@ gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
|||
GST_FORMAT_TIME, *value,
|
||||
format, value);
|
||||
}
|
||||
formats++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -729,22 +700,14 @@ gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
static const GstEventMask*
|
||||
gst_mpeg2dec_get_src_event_masks (GstPad *pad)
|
||||
{
|
||||
static const GstEventMask masks[] = {
|
||||
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH },
|
||||
{ 0, }
|
||||
};
|
||||
return masks;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_BYTES };
|
||||
#define MAX_SEEK_FORMATS 1 /* we can only do time seeking for now */
|
||||
gint i;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
|
@ -755,7 +718,6 @@ gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
|||
gint64 src_offset;
|
||||
gboolean flush;
|
||||
GstFormat format;
|
||||
const GstFormat *peer_formats;
|
||||
|
||||
format = GST_FORMAT_TIME;
|
||||
|
||||
|
@ -775,14 +737,11 @@ gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
|||
/* assume the worst */
|
||||
res = FALSE;
|
||||
|
||||
/* get our peer formats */
|
||||
peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
|
||||
|
||||
/* while we did not exhaust our seek formats without result */
|
||||
while (peer_formats && *peer_formats) {
|
||||
for (i = 0; i < MAX_SEEK_FORMATS && !res; i++) {
|
||||
gint64 desired_offset;
|
||||
|
||||
format = *peer_formats;
|
||||
format = formats[i];
|
||||
|
||||
/* try to convert requested format to one we can seek with on the sinkpad */
|
||||
if (gst_pad_convert (mpeg2dec->sinkpad, GST_FORMAT_TIME, src_offset, &format, &desired_offset))
|
||||
|
@ -790,20 +749,14 @@ gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
|||
GstEvent *seek_event;
|
||||
|
||||
/* conversion succeeded, create the seek */
|
||||
seek_event = gst_event_new_seek (format | GST_SEEK_METHOD_SET | flush, desired_offset);
|
||||
seek_event = gst_event_new_seek (formats[i] | GST_SEEK_METHOD_SET | flush, desired_offset);
|
||||
/* do the seekk */
|
||||
if (gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), seek_event)) {
|
||||
/* seek worked, we're done, loop will exit */
|
||||
res = TRUE;
|
||||
}
|
||||
}
|
||||
peer_formats++;
|
||||
}
|
||||
/* at this point, either the seek worked and res = TRUE or res == FALSE and the seek
|
||||
* failed */
|
||||
if (res && flush) {
|
||||
/* if we need to flush, iterate until the buffer is empty */
|
||||
while (mpeg2_parse (mpeg2dec->decoder) != -1);
|
||||
/* at this point, either the seek worked or res == FALSE */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -825,18 +778,23 @@ gst_mpeg2dec_change_state (GstElement *element)
|
|||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
{
|
||||
gst_mpeg2dec_vo_open (mpeg2dec);
|
||||
mpeg2_init (mpeg2dec->decoder, mpeg2dec->accel, mpeg2dec->vo);
|
||||
|
||||
mpeg2dec->decoder->is_sequence_needed = 1;
|
||||
mpeg2dec->decoder->frame_rate_code = 0;
|
||||
mpeg2dec->next_time = 0;
|
||||
mpeg2dec->peerpool = NULL;
|
||||
mpeg2dec->closed = FALSE;
|
||||
|
||||
/* reset the initial video state */
|
||||
mpeg2dec->format = MPEG2DEC_FORMAT_NONE;
|
||||
mpeg2dec->format = -1;
|
||||
mpeg2dec->width = -1;
|
||||
mpeg2dec->height = -1;
|
||||
mpeg2dec->first = TRUE;
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
mpeg2dec->last_PTS = -1;
|
||||
mpeg2dec->discont_pending = TRUE;
|
||||
mpeg2dec->frame_period = 0;
|
||||
mpeg2dec->adjust = 0;
|
||||
break;
|
||||
}
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
|
@ -859,6 +817,7 @@ gst_mpeg2dec_change_state (GstElement *element)
|
|||
/*mpeg2_close (mpeg2dec->decoder); */
|
||||
mpeg2dec->closed = TRUE;
|
||||
}
|
||||
gst_mpeg2dec_vo_destroy (mpeg2dec);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
|
@ -897,6 +856,7 @@ gst_mpeg2dec_get_property (GObject *object, guint prop_id, GValue *value, GParam
|
|||
|
||||
switch (prop_id) {
|
||||
case ARG_FRAME_RATE:
|
||||
g_value_set_float (value, video_rates[mpeg2dec->frame_rate_code]);
|
||||
break;
|
||||
default:
|
||||
break;
|
|
@ -43,49 +43,34 @@ extern "C" {
|
|||
#define GST_IS_MPEG2DEC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEG2DEC))
|
||||
|
||||
#define MPEGTIME_TO_GSTTIME(time) (((time) * (GST_MSECOND/10)) / 9LL)
|
||||
#define GSTTIME_TO_MPEGTIME(time) (((time) * 9LL) / (GST_MSECOND/10))
|
||||
|
||||
typedef struct _GstMpeg2dec GstMpeg2dec;
|
||||
typedef struct _GstMpeg2decClass GstMpeg2decClass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MPEG2DEC_FORMAT_NONE,
|
||||
MPEG2DEC_FORMAT_I420,
|
||||
MPEG2DEC_FORMAT_YV12,
|
||||
} Mpeg2decFormat;
|
||||
|
||||
struct _GstMpeg2dec {
|
||||
GstElement element;
|
||||
|
||||
/* pads */
|
||||
GstPad *sinkpad,
|
||||
*srcpad;
|
||||
GstPad *sinkpad,*srcpad;
|
||||
GstBufferPool *peerpool;
|
||||
|
||||
mpeg2dec_t *decoder;
|
||||
guint32 accel;
|
||||
vo_instance_t *vo;
|
||||
gboolean closed;
|
||||
|
||||
/* the timestamp of the next frame */
|
||||
gboolean first;
|
||||
gboolean discont_pending;
|
||||
gint64 next_time;
|
||||
gint64 last_PTS;
|
||||
gint frames_per_PTS;
|
||||
gint adjust;
|
||||
|
||||
/* video state */
|
||||
Mpeg2decFormat format;
|
||||
gint format;
|
||||
gint width;
|
||||
gint height;
|
||||
gint pixel_width;
|
||||
gint pixel_height;
|
||||
gint frame_rate_code;
|
||||
gint64 total_frames;
|
||||
gint64 frame_period;
|
||||
|
||||
GstCache *cache;
|
||||
gint cache_id;
|
||||
};
|
||||
|
||||
struct _GstMpeg2decClass {
|
|
@ -22,7 +22,6 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#include <mpeg2dec/mm_accel.h>
|
||||
#include <mpeg2dec/video_out.h>
|
||||
#include "gstmpeg2dec.h"
|
||||
|
||||
/* elementfactory information */
|
||||
|
@ -32,8 +31,8 @@ static GstElementDetails gst_mpeg2dec_details = {
|
|||
"GPL",
|
||||
"Uses libmpeg2 to decode MPEG video streams",
|
||||
VERSION,
|
||||
"David I. Lehn <dlehn@users.sourceforge.net>",
|
||||
"(C) 2000",
|
||||
"Wim Taymans <wim.taymans@chello.be>, "
|
||||
"(C) 2002",
|
||||
};
|
||||
|
||||
/* Mpeg2dec signals and args */
|
||||
|
@ -48,36 +47,27 @@ enum {
|
|||
/* FILL ME */
|
||||
};
|
||||
|
||||
static double video_rates[16] =
|
||||
{
|
||||
0.0,
|
||||
24000.0/1001.,
|
||||
24.0,
|
||||
25.0,
|
||||
30000.0/1001.,
|
||||
30.0,
|
||||
50.0,
|
||||
60000.0/1001.,
|
||||
60.0,
|
||||
1.0,
|
||||
5.0,
|
||||
10.0,
|
||||
12.0,
|
||||
15.0,
|
||||
0.0,
|
||||
0.0
|
||||
};
|
||||
|
||||
GST_PAD_TEMPLATE_FACTORY (src_template_factory,
|
||||
"src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_CAPS_NEW (
|
||||
"mpeg2dec_src",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y','V','1','2')),
|
||||
"width", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"height", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"pixel_width", GST_PROPS_INT_RANGE (1, 255),
|
||||
"pixel_height", GST_PROPS_INT_RANGE (1, 255)
|
||||
),
|
||||
GST_CAPS_NEW (
|
||||
"mpeg2dec_src",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')),
|
||||
"width", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"height", GST_PROPS_INT_RANGE (16, 4096)
|
||||
"height", GST_PROPS_INT_RANGE (16, 4096),
|
||||
"pixel_width", GST_PROPS_INT_RANGE (1, 255),
|
||||
"pixel_height", GST_PROPS_INT_RANGE (1, 255)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -102,11 +92,21 @@ static void gst_mpeg2dec_set_property (GObject *object, guint prop_id,
|
|||
const GValue *value, GParamSpec *pspec);
|
||||
static void gst_mpeg2dec_get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec);
|
||||
static void gst_mpeg2dec_set_cache (GstElement *element, GstCache *cache);
|
||||
static GstCache* gst_mpeg2dec_get_cache (GstElement *element);
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_src_formats (GstPad *pad);
|
||||
static const GstEventMask*
|
||||
gst_mpeg2dec_get_src_event_masks (GstPad *pad);
|
||||
static gboolean gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event);
|
||||
static const GstPadQueryType*
|
||||
gst_mpeg2dec_get_src_query_types (GstPad *pad);
|
||||
static gboolean gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
||||
GstFormat *format, gint64 *value);
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_sink_formats (GstPad *pad);
|
||||
static gboolean gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
GstFormat *dest_format, gint64 *dest_value);
|
||||
static gboolean gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
|
@ -162,237 +162,8 @@ gst_mpeg2dec_class_init(GstMpeg2decClass *klass)
|
|||
gobject_class->dispose = gst_mpeg2dec_dispose;
|
||||
|
||||
gstelement_class->change_state = gst_mpeg2dec_change_state;
|
||||
}
|
||||
|
||||
typedef struct gst_mpeg2dec_vo_frame_s {
|
||||
vo_frame_t vo;
|
||||
|
||||
GstBuffer *buffer;
|
||||
gboolean sent;
|
||||
} gst_mpeg2dec_vo_frame_t;
|
||||
|
||||
#define NUM_FRAMES 3
|
||||
|
||||
typedef struct gst_mpeg2dec_vo_instance_s {
|
||||
vo_instance_t vo;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
gint prediction_index;
|
||||
gst_mpeg2dec_vo_frame_t frames[NUM_FRAMES];
|
||||
} gst_mpeg2dec_vo_instance_t;
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_frame_draw (vo_frame_t * frame)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t *_instance;
|
||||
gst_mpeg2dec_vo_frame_t *_frame;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
gint64 pts = -1;
|
||||
|
||||
g_return_if_fail (frame != NULL);
|
||||
g_return_if_fail (((gst_mpeg2dec_vo_frame_t *)frame)->buffer != NULL);
|
||||
|
||||
_frame = (gst_mpeg2dec_vo_frame_t *)frame;
|
||||
_instance = (gst_mpeg2dec_vo_instance_t *)frame->instance;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (_instance->mpeg2dec);
|
||||
|
||||
|
||||
/* we have to be carefull here. we do mpeg2_close in the READY state
|
||||
* but it can send a few frames still. We have to make sure we are playing
|
||||
* when we send frames. we do have to free those last frames though */
|
||||
if (GST_STATE (GST_ELEMENT (mpeg2dec)) != GST_STATE_PLAYING) {
|
||||
gst_buffer_unref (_frame->buffer);
|
||||
/* pretend we have sent the frame */
|
||||
_frame->sent = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mpeg2dec->frame_rate_code != mpeg2dec->decoder->frame_rate_code)
|
||||
{
|
||||
mpeg2dec->frame_rate_code = mpeg2dec->decoder->frame_rate_code;
|
||||
|
||||
g_object_notify (G_OBJECT (mpeg2dec), "frame_rate");
|
||||
}
|
||||
|
||||
pts = mpeg2dec->next_time - 3 * (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (_frame->buffer) = pts;
|
||||
|
||||
GST_DEBUG (0, "out: %lld %d %lld", GST_BUFFER_TIMESTAMP (_frame->buffer),
|
||||
mpeg2dec->decoder->frame_rate_code,
|
||||
(long long)(GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]));
|
||||
|
||||
mpeg2dec->next_time += (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]) + mpeg2dec->adjust;
|
||||
|
||||
GST_BUFFER_FLAG_SET (_frame->buffer, GST_BUFFER_READONLY);
|
||||
mpeg2dec->frames_per_PTS++;
|
||||
mpeg2dec->first = FALSE;
|
||||
_frame->sent = TRUE;
|
||||
mpeg2dec->total_frames++;
|
||||
gst_pad_push (mpeg2dec->srcpad, _frame->buffer);
|
||||
}
|
||||
|
||||
static int
|
||||
gst_mpeg2dec_vo_setup (vo_instance_t * instance, int width, int height)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * _instance;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
|
||||
g_return_val_if_fail (instance != NULL, -1);
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: setup w=%d h=%d", width, height);
|
||||
|
||||
_instance = (gst_mpeg2dec_vo_instance_t*)instance;
|
||||
mpeg2dec = _instance->mpeg2dec;
|
||||
_instance->prediction_index = 1;
|
||||
mpeg2dec->width = width;
|
||||
mpeg2dec->height = height;
|
||||
mpeg2dec->total_frames = 0;
|
||||
|
||||
gst_pad_try_set_caps (mpeg2dec->srcpad,
|
||||
gst_caps_new (
|
||||
"mpeg2dec_caps",
|
||||
"video/raw",
|
||||
gst_props_new (
|
||||
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')),
|
||||
"width", GST_PROPS_INT (width),
|
||||
"height", GST_PROPS_INT (height),
|
||||
NULL)));
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_close (vo_instance_t * instance)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * _instance;
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: close");
|
||||
|
||||
_instance = (gst_mpeg2dec_vo_instance_t*)instance;
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static vo_frame_t *
|
||||
gst_mpeg2dec_vo_get_frame (vo_instance_t * instance, int flags)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * _instance;
|
||||
gst_mpeg2dec_vo_frame_t *frame;
|
||||
size_t size0;
|
||||
uint8_t *data = NULL;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
|
||||
g_return_val_if_fail (instance != NULL, NULL);
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: get_frame");
|
||||
|
||||
_instance = (gst_mpeg2dec_vo_instance_t *)instance;
|
||||
|
||||
mpeg2dec = _instance->mpeg2dec;
|
||||
|
||||
if (flags & VO_PREDICTION_FLAG) {
|
||||
_instance->prediction_index ^= 1;
|
||||
frame = &_instance->frames[_instance->prediction_index];
|
||||
} else {
|
||||
frame = &_instance->frames[2];
|
||||
}
|
||||
|
||||
/* we are reusing this frame */
|
||||
if (frame->buffer != NULL) {
|
||||
/* if the frame wasn't sent, we have to unref twice */
|
||||
if (!frame->sent)
|
||||
gst_buffer_unref (frame->buffer);
|
||||
gst_buffer_unref (frame->buffer);
|
||||
frame->buffer = NULL;
|
||||
}
|
||||
|
||||
size0 = mpeg2dec->width * mpeg2dec->height / 4;
|
||||
|
||||
if (mpeg2dec->peerpool) {
|
||||
frame->buffer = gst_buffer_new_from_pool (mpeg2dec->peerpool, 0, 0);
|
||||
} else {
|
||||
size_t size = 6 * size0;
|
||||
size_t offset;
|
||||
GstBuffer *parent;
|
||||
|
||||
parent = gst_buffer_new ();
|
||||
|
||||
GST_BUFFER_SIZE(parent) = size + 0x10;
|
||||
GST_BUFFER_DATA(parent) = data = g_new(uint8_t, size + 0x10);
|
||||
|
||||
offset = 0x10 - (((unsigned long)data) & 0xf);
|
||||
frame->buffer = gst_buffer_create_sub(parent, offset, size);
|
||||
|
||||
gst_buffer_unref(parent);
|
||||
}
|
||||
data = GST_BUFFER_DATA(frame->buffer);
|
||||
|
||||
/* need ref=2 */
|
||||
/* 1 - unref when reusing this frame */
|
||||
/* 2 - unref when other elements done with buffer */
|
||||
gst_buffer_ref (frame->buffer);
|
||||
|
||||
frame->vo.base[0] = data;
|
||||
frame->vo.base[1] = data + 4 * size0;
|
||||
frame->vo.base[2] = data + 5 * size0;
|
||||
/*printf("base[0]=%p\n", frame->vo.base[0]); */
|
||||
frame->sent = FALSE;
|
||||
|
||||
return (vo_frame_t *)frame;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_open (GstMpeg2dec *mpeg2dec)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * instance;
|
||||
gint i,j;
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: open");
|
||||
|
||||
instance = g_new (gst_mpeg2dec_vo_instance_t, 1);
|
||||
|
||||
instance->vo.setup = gst_mpeg2dec_vo_setup;
|
||||
instance->vo.close = gst_mpeg2dec_vo_close;
|
||||
instance->vo.get_frame = gst_mpeg2dec_vo_get_frame;
|
||||
instance->mpeg2dec = mpeg2dec;
|
||||
|
||||
for (i=0; i<NUM_FRAMES; i++) {
|
||||
for (j=0; j<3; j++) {
|
||||
instance->frames[j].vo.base[j] = NULL;
|
||||
}
|
||||
instance->frames[i].vo.copy = NULL;
|
||||
instance->frames[i].vo.field = NULL;
|
||||
instance->frames[i].vo.draw = gst_mpeg2dec_vo_frame_draw;
|
||||
instance->frames[i].vo.instance = (vo_instance_t *)instance;
|
||||
instance->frames[i].buffer = NULL;
|
||||
}
|
||||
|
||||
mpeg2dec->vo = (vo_instance_t *) instance;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_vo_destroy (GstMpeg2dec *mpeg2dec)
|
||||
{
|
||||
gst_mpeg2dec_vo_instance_t * instance;
|
||||
gint i;
|
||||
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "VO: destroy");
|
||||
|
||||
instance = (gst_mpeg2dec_vo_instance_t *) mpeg2dec->vo;
|
||||
|
||||
for (i=0; i<NUM_FRAMES; i++) {
|
||||
if (instance->frames[i].buffer) {
|
||||
if (!instance->frames[i].sent) {
|
||||
gst_buffer_unref (instance->frames[i].buffer);
|
||||
}
|
||||
gst_buffer_unref (instance->frames[i].buffer);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (instance);
|
||||
mpeg2dec->vo = NULL;
|
||||
gstelement_class->set_cache = gst_mpeg2dec_set_cache;
|
||||
gstelement_class->get_cache = gst_mpeg2dec_get_cache;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -402,20 +173,22 @@ gst_mpeg2dec_init (GstMpeg2dec *mpeg2dec)
|
|||
mpeg2dec->sinkpad = gst_pad_new_from_template (
|
||||
GST_PAD_TEMPLATE_GET (sink_template_factory), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->sinkpad);
|
||||
gst_pad_set_chain_function (mpeg2dec->sinkpad, gst_mpeg2dec_chain);
|
||||
gst_pad_set_convert_function (mpeg2dec->sinkpad, gst_mpeg2dec_convert_sink);
|
||||
gst_pad_set_chain_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_chain));
|
||||
gst_pad_set_formats_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_sink_formats));
|
||||
gst_pad_set_convert_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_convert_sink));
|
||||
|
||||
mpeg2dec->srcpad = gst_pad_new_from_template (
|
||||
GST_PAD_TEMPLATE_GET (src_template_factory), "src");
|
||||
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->srcpad);
|
||||
gst_pad_set_formats_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_formats));
|
||||
gst_pad_set_event_mask_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_event_masks));
|
||||
gst_pad_set_event_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_event));
|
||||
gst_pad_set_query_type_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_query_types));
|
||||
gst_pad_set_query_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_query));
|
||||
gst_pad_set_convert_function (mpeg2dec->srcpad, gst_mpeg2dec_convert_src);
|
||||
gst_pad_set_convert_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_convert_src));
|
||||
|
||||
/* initialize the mpeg2dec decoder state */
|
||||
mpeg2dec->decoder = g_new (mpeg2dec_t, 1);
|
||||
mpeg2dec->decoder->frame_rate_code = 0;
|
||||
mpeg2dec->accel = mm_accel();
|
||||
mpeg2dec->decoder = mpeg2_init (mm_accel());
|
||||
|
||||
GST_FLAG_SET (GST_ELEMENT (mpeg2dec), GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
@ -425,21 +198,140 @@ gst_mpeg2dec_dispose (GObject *object)
|
|||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
|
||||
|
||||
g_free (mpeg2dec->decoder);
|
||||
if (!mpeg2dec->closed)
|
||||
mpeg2_close (mpeg2dec->decoder);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_set_cache (GstElement *element, GstCache *cache)
|
||||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
|
||||
|
||||
mpeg2dec->cache = cache;
|
||||
|
||||
gst_cache_get_writer_id (cache, GST_OBJECT (element), &mpeg2dec->cache_id);
|
||||
}
|
||||
|
||||
static GstCache*
|
||||
gst_mpeg2dec_get_cache (GstElement *element)
|
||||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
|
||||
|
||||
return mpeg2dec->cache;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_alloc_buffer (GstMpeg2dec *mpeg2dec, const mpeg2_info_t *info)
|
||||
{
|
||||
GstBuffer *outbuf = NULL;
|
||||
gint size = mpeg2dec->width * mpeg2dec->height;
|
||||
guint8 *buf[3], *out;
|
||||
const picture_t *picture;
|
||||
|
||||
if (mpeg2dec->peerpool) {
|
||||
outbuf = gst_buffer_new_from_pool (mpeg2dec->peerpool, 0, 0);
|
||||
}
|
||||
if (!outbuf) {
|
||||
outbuf = gst_buffer_new_and_alloc ((size * 3) / 2);
|
||||
}
|
||||
|
||||
out = GST_BUFFER_DATA (outbuf);
|
||||
|
||||
buf[0] = out;
|
||||
if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) {
|
||||
buf[1] = buf[0] + size;
|
||||
buf[2] = buf[1] + size/4;
|
||||
}
|
||||
else {
|
||||
buf[2] = buf[0] + size;
|
||||
buf[1] = buf[2] + size/4;
|
||||
}
|
||||
|
||||
gst_buffer_ref (outbuf);
|
||||
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
|
||||
|
||||
picture = info->current_picture;
|
||||
|
||||
if (picture && (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I)
|
||||
{
|
||||
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
|
||||
}
|
||||
else {
|
||||
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_KEY_UNIT);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_negotiate_format (GstMpeg2dec *mpeg2dec)
|
||||
{
|
||||
GstCaps *allowed;
|
||||
GstCaps *trylist;
|
||||
|
||||
/* we what we are allowed to do */
|
||||
allowed = gst_pad_get_allowed_caps (mpeg2dec->srcpad);
|
||||
/* we could not get allowed caps */
|
||||
if (!allowed) {
|
||||
allowed = GST_CAPS_NEW (
|
||||
"mpeg2dec_negotiate",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
|
||||
);
|
||||
}
|
||||
|
||||
/* try to fix our height */
|
||||
trylist = gst_caps_intersect (allowed,
|
||||
GST_CAPS_NEW (
|
||||
"mpeg2dec_negotiate",
|
||||
"video/raw",
|
||||
"width", GST_PROPS_INT (mpeg2dec->width),
|
||||
"height", GST_PROPS_INT (mpeg2dec->height),
|
||||
"pixel_width", GST_PROPS_INT (mpeg2dec->pixel_width),
|
||||
"pixel_height", GST_PROPS_INT (mpeg2dec->pixel_height)
|
||||
));
|
||||
/* prepare for looping */
|
||||
trylist = gst_caps_normalize (trylist);
|
||||
|
||||
while (trylist) {
|
||||
GstCaps *to_try = gst_caps_copy_1 (trylist);
|
||||
|
||||
/* try each format */
|
||||
if (gst_pad_try_set_caps (mpeg2dec->srcpad, to_try) > 0) {
|
||||
guint32 fourcc;
|
||||
|
||||
/* it worked, try to find what it was again */
|
||||
gst_caps_get_fourcc_int (to_try, "format", &fourcc);
|
||||
|
||||
if (fourcc == GST_STR_FOURCC ("I420")) {
|
||||
mpeg2dec->format = MPEG2DEC_FORMAT_I420;
|
||||
}
|
||||
else {
|
||||
mpeg2dec->format = MPEG2DEC_FORMAT_YV12;
|
||||
}
|
||||
break;
|
||||
}
|
||||
trylist = trylist->next;
|
||||
}
|
||||
/* oops list exhausted and nothing was found... */
|
||||
if (!trylist) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg2dec_chain (GstPad *pad, GstBuffer *buf)
|
||||
{
|
||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
guint32 size;
|
||||
guchar *data;
|
||||
guint num_frames;
|
||||
guint8 *data, *end;
|
||||
gint64 pts;
|
||||
|
||||
GST_DEBUG (0, "MPEG2DEC: chain called");
|
||||
const mpeg2_info_t *info;
|
||||
gint state;
|
||||
gboolean done = FALSE;
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
@ -449,18 +341,16 @@ gst_mpeg2dec_chain (GstPad *pad, GstBuffer *buf)
|
|||
{
|
||||
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
//mpeg2dec->decoder->is_sequence_needed = 1;
|
||||
GST_DEBUG (GST_CAT_EVENT, "mpeg2dec: discont\n");
|
||||
GST_DEBUG (GST_CAT_EVENT, "discont\n");
|
||||
mpeg2dec->first = TRUE;
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
mpeg2dec->last_PTS = -1;
|
||||
mpeg2dec->adjust = 0;
|
||||
mpeg2dec->next_time = 0;
|
||||
mpeg2dec->discont_pending = TRUE;
|
||||
gst_pad_event_default (pad, event);
|
||||
return;
|
||||
}
|
||||
case GST_EVENT_EOS:
|
||||
if (!mpeg2dec->closed) {
|
||||
/* close flushes the last few frames */
|
||||
mpeg2_close (mpeg2dec->decoder);
|
||||
mpeg2dec->closed = TRUE;
|
||||
}
|
||||
|
@ -473,74 +363,187 @@ gst_mpeg2dec_chain (GstPad *pad, GstBuffer *buf)
|
|||
size = GST_BUFFER_SIZE (buf);
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
pts = GST_BUFFER_TIMESTAMP (buf);
|
||||
/* rationale for these heuristics;
|
||||
* - we keep our own timestamp guestimate in next_time, this is based on the
|
||||
* frame rate of the video stream.
|
||||
* - we receive PTS values in the buffer timestamp.
|
||||
* - we only accept new pts values if they are monotonically increasing.
|
||||
* - if we have more than 10 frames without a new PTS value, we compare our
|
||||
* internal counter to the PTS and calculate a diff. This is usefull when the
|
||||
* framerate in the stream is wrong.
|
||||
* - if the PTS and our own counter are adrift bu more than 10 frames, we assume
|
||||
* a discontinuity in the PTS and adjust our own counter.
|
||||
*/
|
||||
GST_DEBUG (GST_CAT_CLOCK, "mpeg2dec: pts %llu\n", pts);
|
||||
if (!mpeg2dec->first) {
|
||||
if (mpeg2dec->last_PTS < pts) {
|
||||
|
||||
if (pts != mpeg2dec->next_time && mpeg2dec->frames_per_PTS > 10) {
|
||||
gint64 diff = ABS (pts - mpeg2dec->last_PTS);
|
||||
info = mpeg2_info (mpeg2dec->decoder);
|
||||
end = data + size;
|
||||
|
||||
if (diff > (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]) + GST_SECOND/1000) {
|
||||
mpeg2dec->adjust = (diff / mpeg2dec->frames_per_PTS +1) -
|
||||
(GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code]);
|
||||
}
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
}
|
||||
if (ABS (pts - mpeg2dec->last_PTS) > (GST_SECOND / video_rates[mpeg2dec->decoder->frame_rate_code])*10) {
|
||||
if (pts != -1) {
|
||||
gint64 mpeg_pts = GSTTIME_TO_MPEGTIME (pts);
|
||||
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
}
|
||||
if (mpeg2dec->next_time < pts) {
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
/*
|
||||
if (mpeg2dec->last_PTS < pts) {
|
||||
mpeg2dec->next_time = pts;
|
||||
g_print ("** adjust next_time %lld %lld\n", mpeg2dec->last_PTS, pts);
|
||||
}
|
||||
*/
|
||||
GST_DEBUG (0, "have pts: %lld (%lld)",
|
||||
mpeg_pts, MPEGTIME_TO_GSTTIME (mpeg_pts));
|
||||
|
||||
mpeg2_pts (mpeg2dec->decoder, mpeg_pts);
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (GST_CAT_CLOCK, "no pts");
|
||||
}
|
||||
|
||||
mpeg2_buffer (mpeg2dec->decoder, data, end);
|
||||
|
||||
while (!done) {
|
||||
state = mpeg2_parse (mpeg2dec->decoder);
|
||||
switch (state) {
|
||||
case STATE_SEQUENCE:
|
||||
{
|
||||
mpeg2dec->width = info->sequence->width;
|
||||
mpeg2dec->height = info->sequence->height;
|
||||
mpeg2dec->pixel_width = info->sequence->pixel_width;
|
||||
mpeg2dec->pixel_height = info->sequence->pixel_height;
|
||||
mpeg2dec->total_frames = 0;
|
||||
mpeg2dec->frame_period = info->sequence->frame_period * GST_USECOND / 27;
|
||||
|
||||
GST_DEBUG (0, "sequence flags: %d, frame period: %d",
|
||||
info->sequence->flags, info->sequence->frame_period);
|
||||
|
||||
if (!gst_mpeg2dec_negotiate_format (mpeg2dec)) {
|
||||
gst_element_error (GST_ELEMENT (mpeg2dec), "could not negotiate format");
|
||||
return;
|
||||
}
|
||||
|
||||
gst_mpeg2dec_alloc_buffer (mpeg2dec, info);
|
||||
break;
|
||||
}
|
||||
case STATE_SEQUENCE_REPEATED:
|
||||
GST_DEBUG (0, "sequence repeated");
|
||||
break;
|
||||
case STATE_GOP:
|
||||
break;
|
||||
case STATE_PICTURE:
|
||||
{
|
||||
gboolean key_frame = FALSE;
|
||||
|
||||
|
||||
if (info->current_picture)
|
||||
key_frame = (info->current_picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
|
||||
|
||||
gst_mpeg2dec_alloc_buffer (mpeg2dec, info);
|
||||
|
||||
if (key_frame && mpeg2dec->discont_pending) {
|
||||
mpeg2dec->discont_pending = FALSE;
|
||||
mpeg2dec->first = TRUE;
|
||||
if (pts != -1 && mpeg2dec->last_PTS == -1) {
|
||||
mpeg2dec->last_PTS = pts;
|
||||
mpeg2dec->next_time = pts;
|
||||
}
|
||||
}
|
||||
|
||||
if (mpeg2dec->cache && pts != GST_CLOCK_TIME_NONE) {
|
||||
gst_cache_add_association (mpeg2dec->cache, mpeg2dec->cache_id,
|
||||
(key_frame ? GST_ACCOCIATION_FLAG_KEY_UNIT : 0),
|
||||
GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buf),
|
||||
GST_FORMAT_TIME, pts, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_SLICE_1ST:
|
||||
GST_DEBUG (0, "slice 1st");
|
||||
break;
|
||||
case STATE_PICTURE_2ND:
|
||||
GST_DEBUG (0, "picture second\n");
|
||||
break;
|
||||
case STATE_SLICE:
|
||||
case STATE_END:
|
||||
{
|
||||
GstBuffer *outbuf = NULL;
|
||||
|
||||
/* fprintf(stderr, "MPEG2DEC: in timestamp=%llu\n",GST_BUFFER_TIMESTAMP(buf)); */
|
||||
/* fprintf(stderr, "MPEG2DEC: have buffer of %d bytes\n",size); */
|
||||
num_frames = mpeg2_decode_data(mpeg2dec->decoder, data, data + size);
|
||||
/*fprintf(stderr, "MPEG2DEC: decoded %d frames\n", num_frames);*/
|
||||
if (info->display_fbuf && info->display_fbuf->id) {
|
||||
const picture_t *picture;
|
||||
|
||||
outbuf = (GstBuffer *) info->display_fbuf->id;
|
||||
picture = info->display_picture;
|
||||
|
||||
if (picture->flags & PIC_FLAG_PTS) {
|
||||
GstClockTime time = MPEGTIME_TO_GSTTIME (picture->pts);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = time;
|
||||
|
||||
mpeg2dec->next_time = time;
|
||||
}
|
||||
else {
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = mpeg2dec->next_time;
|
||||
}
|
||||
mpeg2dec->next_time += (mpeg2dec->frame_period * picture->nb_fields) >> 1;
|
||||
|
||||
GST_DEBUG (0, "picture: %s %s fields:%d ts:%lld",
|
||||
(picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff " : " "),
|
||||
(picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "),
|
||||
picture->nb_fields,
|
||||
GST_BUFFER_TIMESTAMP (outbuf));
|
||||
|
||||
/*
|
||||
if (picture->flags & PIC_FLAG_SKIP ||
|
||||
mpeg2dec->discont_pending ||
|
||||
(mpeg2dec->first && !GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_KEY_UNIT)))
|
||||
{
|
||||
*/
|
||||
if (picture->flags & PIC_FLAG_SKIP ||
|
||||
!GST_PAD_IS_USABLE (mpeg2dec->srcpad)) {
|
||||
gst_buffer_unref (outbuf);
|
||||
}
|
||||
else {
|
||||
mpeg2dec->first = FALSE;
|
||||
gst_pad_push (mpeg2dec->srcpad, outbuf);
|
||||
}
|
||||
}
|
||||
if (info->discard_fbuf && info->discard_fbuf->id) {
|
||||
gst_buffer_unref ((GstBuffer *)info->discard_fbuf->id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/* need more data */
|
||||
case -1:
|
||||
done = TRUE;
|
||||
break;
|
||||
/* error */
|
||||
case STATE_INVALID:
|
||||
gst_element_error (GST_ELEMENT (mpeg2dec), "fatal error");
|
||||
done = TRUE;
|
||||
break;
|
||||
default:
|
||||
g_warning ("%s: unhandled state %d, FIXME",
|
||||
gst_element_get_name (GST_ELEMENT (mpeg2dec)),
|
||||
state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gst_buffer_unref(buf);
|
||||
}
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_sink_formats (GstPad *pad)
|
||||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_BYTES,
|
||||
GST_FORMAT_TIME,
|
||||
0
|
||||
};
|
||||
return formats;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
GstFormat *dest_format, gint64 *dest_value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
const mpeg2_info_t *info;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
info = mpeg2_info (mpeg2dec->decoder);
|
||||
|
||||
switch (src_format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
switch (*dest_format) {
|
||||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_TIME;
|
||||
case GST_FORMAT_TIME:
|
||||
if (info->sequence && info->sequence->byte_rate) {
|
||||
*dest_value = GST_SECOND * src_value / info->sequence->byte_rate;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
@ -550,6 +553,10 @@ gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_BYTES;
|
||||
case GST_FORMAT_BYTES:
|
||||
if (info->sequence && info->sequence->byte_rate) {
|
||||
*dest_value = src_value * info->sequence->byte_rate / GST_SECOND;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
@ -560,15 +567,31 @@ gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
return res;
|
||||
}
|
||||
|
||||
static const GstFormat*
|
||||
gst_mpeg2dec_get_src_formats (GstPad *pad)
|
||||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_BYTES,
|
||||
GST_FORMAT_TIME,
|
||||
GST_FORMAT_UNITS,
|
||||
0
|
||||
};
|
||||
return formats;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||
GstFormat *dest_format, gint64 *dest_value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
const mpeg2_info_t *info;
|
||||
guint64 scale = 1;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
info = mpeg2_info (mpeg2dec->decoder);
|
||||
|
||||
switch (src_format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
switch (*dest_format) {
|
||||
|
@ -584,12 +607,12 @@ gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_BYTES;
|
||||
case GST_FORMAT_BYTES:
|
||||
*dest_value = src_value * 6 * (mpeg2dec->width * mpeg2dec->height >> 2) *
|
||||
video_rates[mpeg2dec->decoder->frame_rate_code] / GST_SECOND;
|
||||
break;
|
||||
scale = 6 * (mpeg2dec->width * mpeg2dec->height >> 2);
|
||||
case GST_FORMAT_UNITS:
|
||||
*dest_value = src_value * video_rates[mpeg2dec->decoder->frame_rate_code] / GST_SECOND;
|
||||
if (info->sequence && mpeg2dec->frame_period) {
|
||||
*dest_value = src_value * scale / mpeg2dec->frame_period;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
@ -599,18 +622,10 @@ gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
case GST_FORMAT_DEFAULT:
|
||||
*dest_format = GST_FORMAT_TIME;
|
||||
case GST_FORMAT_TIME:
|
||||
if (video_rates[mpeg2dec->decoder->frame_rate_code] != 0.0) {
|
||||
*dest_value = src_value * GST_SECOND /
|
||||
video_rates[mpeg2dec->decoder->frame_rate_code];
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
*dest_value = src_value * mpeg2dec->frame_period;
|
||||
break;
|
||||
case GST_FORMAT_BYTES:
|
||||
*dest_value = src_value * 6 * (mpeg2dec->width * mpeg2dec->height >> 2);
|
||||
break;
|
||||
case GST_FORMAT_UNITS:
|
||||
*dest_value = src_value;
|
||||
*dest_value = src_value * 6 * ((mpeg2dec->width * mpeg2dec->height) >> 2);
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
|
@ -622,15 +637,24 @@ gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
return res;
|
||||
}
|
||||
|
||||
static const GstPadQueryType*
|
||||
gst_mpeg2dec_get_src_query_types (GstPad *pad)
|
||||
{
|
||||
static const GstPadQueryType types[] = {
|
||||
GST_PAD_QUERY_TOTAL,
|
||||
GST_PAD_QUERY_POSITION,
|
||||
0
|
||||
};
|
||||
return types;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
||||
GstFormat *format, gint64 *value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_BYTES };
|
||||
#define MAX_SEEK_FORMATS 1 /* we can only do time seeking for now */
|
||||
gint i;
|
||||
static const GstFormat *formats;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
|
@ -647,11 +671,15 @@ gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
|||
{
|
||||
res = FALSE;
|
||||
|
||||
for (i = 0; i < MAX_SEEK_FORMATS && !res; i++) {
|
||||
/* get our peer formats */
|
||||
formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
|
||||
|
||||
/* while we did not exhaust our seek formats without result */
|
||||
while (formats && *formats) {
|
||||
GstFormat peer_format;
|
||||
gint64 peer_value;
|
||||
|
||||
peer_format = formats[i];
|
||||
peer_format = *formats;
|
||||
|
||||
/* do the probe */
|
||||
if (gst_pad_query (GST_PAD_PEER (mpeg2dec->sinkpad), GST_PAD_QUERY_TOTAL,
|
||||
|
@ -669,6 +697,7 @@ gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
|||
GST_FORMAT_TIME, *value,
|
||||
format, value);
|
||||
}
|
||||
formats++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -700,14 +729,22 @@ gst_mpeg2dec_src_query (GstPad *pad, GstPadQueryType type,
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
static const GstEventMask*
|
||||
gst_mpeg2dec_get_src_event_masks (GstPad *pad)
|
||||
{
|
||||
static const GstEventMask masks[] = {
|
||||
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH },
|
||||
{ 0, }
|
||||
};
|
||||
return masks;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMpeg2dec *mpeg2dec;
|
||||
static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_BYTES };
|
||||
#define MAX_SEEK_FORMATS 1 /* we can only do time seeking for now */
|
||||
gint i;
|
||||
|
||||
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||
|
||||
|
@ -718,6 +755,7 @@ gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
|||
gint64 src_offset;
|
||||
gboolean flush;
|
||||
GstFormat format;
|
||||
const GstFormat *peer_formats;
|
||||
|
||||
format = GST_FORMAT_TIME;
|
||||
|
||||
|
@ -737,11 +775,14 @@ gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
|||
/* assume the worst */
|
||||
res = FALSE;
|
||||
|
||||
/* get our peer formats */
|
||||
peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
|
||||
|
||||
/* while we did not exhaust our seek formats without result */
|
||||
for (i = 0; i < MAX_SEEK_FORMATS && !res; i++) {
|
||||
while (peer_formats && *peer_formats) {
|
||||
gint64 desired_offset;
|
||||
|
||||
format = formats[i];
|
||||
format = *peer_formats;
|
||||
|
||||
/* try to convert requested format to one we can seek with on the sinkpad */
|
||||
if (gst_pad_convert (mpeg2dec->sinkpad, GST_FORMAT_TIME, src_offset, &format, &desired_offset))
|
||||
|
@ -749,14 +790,20 @@ gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
|
|||
GstEvent *seek_event;
|
||||
|
||||
/* conversion succeeded, create the seek */
|
||||
seek_event = gst_event_new_seek (formats[i] | GST_SEEK_METHOD_SET | flush, desired_offset);
|
||||
seek_event = gst_event_new_seek (format | GST_SEEK_METHOD_SET | flush, desired_offset);
|
||||
/* do the seekk */
|
||||
if (gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), seek_event)) {
|
||||
/* seek worked, we're done, loop will exit */
|
||||
res = TRUE;
|
||||
}
|
||||
}
|
||||
/* at this point, either the seek worked or res == FALSE */
|
||||
peer_formats++;
|
||||
}
|
||||
/* at this point, either the seek worked and res = TRUE or res == FALSE and the seek
|
||||
* failed */
|
||||
if (res && flush) {
|
||||
/* if we need to flush, iterate until the buffer is empty */
|
||||
while (mpeg2_parse (mpeg2dec->decoder) != -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -778,23 +825,18 @@ gst_mpeg2dec_change_state (GstElement *element)
|
|||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
{
|
||||
gst_mpeg2dec_vo_open (mpeg2dec);
|
||||
mpeg2_init (mpeg2dec->decoder, mpeg2dec->accel, mpeg2dec->vo);
|
||||
|
||||
mpeg2dec->decoder->is_sequence_needed = 1;
|
||||
mpeg2dec->decoder->frame_rate_code = 0;
|
||||
mpeg2dec->next_time = 0;
|
||||
mpeg2dec->peerpool = NULL;
|
||||
mpeg2dec->closed = FALSE;
|
||||
|
||||
/* reset the initial video state */
|
||||
mpeg2dec->format = -1;
|
||||
mpeg2dec->format = MPEG2DEC_FORMAT_NONE;
|
||||
mpeg2dec->width = -1;
|
||||
mpeg2dec->height = -1;
|
||||
mpeg2dec->first = TRUE;
|
||||
mpeg2dec->frames_per_PTS = 0;
|
||||
mpeg2dec->last_PTS = -1;
|
||||
mpeg2dec->adjust = 0;
|
||||
mpeg2dec->discont_pending = TRUE;
|
||||
mpeg2dec->frame_period = 0;
|
||||
break;
|
||||
}
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
|
@ -817,7 +859,6 @@ gst_mpeg2dec_change_state (GstElement *element)
|
|||
/*mpeg2_close (mpeg2dec->decoder); */
|
||||
mpeg2dec->closed = TRUE;
|
||||
}
|
||||
gst_mpeg2dec_vo_destroy (mpeg2dec);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
|
@ -856,7 +897,6 @@ gst_mpeg2dec_get_property (GObject *object, guint prop_id, GValue *value, GParam
|
|||
|
||||
switch (prop_id) {
|
||||
case ARG_FRAME_RATE:
|
||||
g_value_set_float (value, video_rates[mpeg2dec->frame_rate_code]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -43,34 +43,49 @@ extern "C" {
|
|||
#define GST_IS_MPEG2DEC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEG2DEC))
|
||||
|
||||
#define MPEGTIME_TO_GSTTIME(time) (((time) * (GST_MSECOND/10)) / 9LL)
|
||||
#define GSTTIME_TO_MPEGTIME(time) (((time) * 9LL) / (GST_MSECOND/10))
|
||||
|
||||
typedef struct _GstMpeg2dec GstMpeg2dec;
|
||||
typedef struct _GstMpeg2decClass GstMpeg2decClass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MPEG2DEC_FORMAT_NONE,
|
||||
MPEG2DEC_FORMAT_I420,
|
||||
MPEG2DEC_FORMAT_YV12,
|
||||
} Mpeg2decFormat;
|
||||
|
||||
struct _GstMpeg2dec {
|
||||
GstElement element;
|
||||
|
||||
/* pads */
|
||||
GstPad *sinkpad,*srcpad;
|
||||
GstPad *sinkpad,
|
||||
*srcpad;
|
||||
GstBufferPool *peerpool;
|
||||
|
||||
mpeg2dec_t *decoder;
|
||||
guint32 accel;
|
||||
vo_instance_t *vo;
|
||||
gboolean closed;
|
||||
|
||||
/* the timestamp of the next frame */
|
||||
gboolean first;
|
||||
gboolean discont_pending;
|
||||
gint64 next_time;
|
||||
gint64 last_PTS;
|
||||
gint frames_per_PTS;
|
||||
gint adjust;
|
||||
|
||||
/* video state */
|
||||
gint format;
|
||||
Mpeg2decFormat format;
|
||||
gint width;
|
||||
gint height;
|
||||
gint pixel_width;
|
||||
gint pixel_height;
|
||||
gint frame_rate_code;
|
||||
gint64 total_frames;
|
||||
gint64 frame_period;
|
||||
|
||||
GstCache *cache;
|
||||
gint cache_id;
|
||||
};
|
||||
|
||||
struct _GstMpeg2decClass {
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
dnl MPEG2DEC_CHECK-LIBHEADER(FEATURE-NAME, LIB-NAME, LIB-FUNCTION, HEADER-NAME,
|
||||
dnl ACTION-IF-FOUND, ACTION-IF-NOT-FOUND,
|
||||
dnl EXTRA-LDFLAGS, EXTRA-CPPFLAGS, INCLUDES)
|
||||
dnl
|
||||
dnl FEATURE-NAME - feature name; library and header files are treated
|
||||
dnl as feature, which we look for
|
||||
dnl LIB-NAME - library name as in AC_CHECK_LIB macro
|
||||
dnl LIB-FUNCTION - library symbol as in AC_CHECK_LIB macro
|
||||
dnl HEADER-NAME - header file name as in AC_CHECK_HEADER
|
||||
dnl ACTION-IF-FOUND - when feature is found then execute given action
|
||||
dnl ACTION-IF-NOT-FOUND - when feature is not found then execute given action
|
||||
dnl EXTRA-LDFLAGS - extra linker flags (-L or -l)
|
||||
dnl EXTRA-CPPFLAGS - extra C preprocessor flags, i.e. -I/usr/X11R6/include
|
||||
dnl INCLUDES - Any #include lines which need to be placed before the
|
||||
dnl header so that it works.
|
||||
dnl
|
||||
dnl Based on GST_CHECK_LIBHEADER from gstreamer plugins 0.3.1.
|
||||
dnl
|
||||
AC_DEFUN(MPEG2DEC_CHECK_LIBHEADER,
|
||||
[
|
||||
AC_CHECK_LIB([$2], [$3], HAVE_[$1]=yes, HAVE_[$1]=no, [$7])
|
||||
check_libheader_feature_name=translit([$1], A-Z, a-z)
|
||||
|
||||
if test "x$HAVE_[$1]" = "xyes"; then
|
||||
check_libheader_save_CPPFLAGS=$CPPFLAGS
|
||||
CPPFLAGS="[$8] $CPPFLAGS"
|
||||
AC_CHECK_HEADER([$4], :, HAVE_[$1]=no, [$9])
|
||||
CPPFLAGS=$check_libheader_save_CPPFLAGS
|
||||
fi
|
||||
|
||||
if test "x$HAVE_[$1]" = "xyes"; then
|
||||
ifelse([$5], , :, [$5])
|
||||
else
|
||||
ifelse([$6], , :, [$6])
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
dnl
|
||||
dnl AC_CHECK_MPEG2DEC(ACTION-IF-FOUND, ACTION-IF-NOT-FOUND)
|
||||
dnl
|
||||
dnl ACTION-IF-FOUND - when feature is found then execute given action
|
||||
dnl ACTION-IF-NOT-FOUND - when feature is not found then execute given action
|
||||
dnl
|
||||
dnl Defines HAVE_MPEG2DEC to yes if mpeg2dec is found
|
||||
dnl
|
||||
dnl CFLAGS and LDFLAGS for the library are stored in MPEG2DEC_CFLAGS and
|
||||
dnl MPEG2DEC_LIBS, respectively
|
||||
dnl
|
||||
dnl Based on GST_CHECK_MPEG2DEC from gstreamer plugins 0.3.3.1
|
||||
dnl Thomas Vander Stichele <thomas@apestaart.org>, Andy Wingo <wingo@pobox.com>
|
||||
dnl
|
||||
AC_DEFUN(AC_CHECK_MPEG2DEC,
|
||||
[dnl
|
||||
AC_ARG_WITH(mpeg2dec-prefix,
|
||||
AC_HELP_STRING([--with-mpeg2dec-prefix=PFX],
|
||||
[prefix where mpeg2dec is installed (optional)]),
|
||||
mpeg2dec_config_prefix="$withval", mpeg2dec_config_prefix="")
|
||||
|
||||
if test x$mpeg2dec_config_prefix = x ; then
|
||||
MPEG2DEC_CHECK_LIBHEADER(CPUACCEL, cpuaccel, mm_accel, mpeg2dec/mm_accel.h)
|
||||
MPEG2DEC_CHECK_LIBHEADER(MPEG2DEC, mpeg2, mpeg2_init, mpeg2dec/mpeg2.h,
|
||||
MPEG2DEC_LIBS="-lmpeg2 -lcpuaccel",, -lcpuaccel, , [
|
||||
#include <inttypes.h>
|
||||
#include <mpeg2dec/mm_accel.h>
|
||||
#include <mpeg2dec/video_out.h>
|
||||
])
|
||||
else
|
||||
MPEG2DEC_CHECK_LIBHEADER(CPUACCEL, cpuaccel, mm_accel, mpeg2dec/mm_accel.h,
|
||||
,, -L$mpeg2dec_config_prefix/lib, -I$mpeg2dec_config_prefix/include)
|
||||
MPEG2DEC_CHECK_LIBHEADER(MPEG2DEC, mpeg2, mpeg2_init, mpeg2dec/mpeg2.h, [
|
||||
MPEG2DEC_LIBS="-lmpeg2 -lcpuaccel -L$mpeg2dec_config_prefix/lib"
|
||||
MPEG2DEC_CFLAGS="-I$mpeg2dec_config_prefix/include"
|
||||
], , -L$mpeg2dec_config_prefix/lib -lcpuaccel,
|
||||
-I$mpeg2dec_config_prefix/include, [
|
||||
#include <inttypes.h>
|
||||
#include <mpeg2dec/mm_accel.h>
|
||||
#include <mpeg2dec/video_out.h>
|
||||
])
|
||||
fi
|
||||
|
||||
if test "x$HAVE_MPEG2DEC" = "xyes"; then
|
||||
if test "x$HAVE_CPUACCEL" = "xyes"; then
|
||||
ifelse([$1], , :, [$1])
|
||||
else
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
else
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
|
||||
AC_SUBST(MPEG2DEC_CFLAGS)
|
||||
AC_SUBST(MPEG2DEC_LIBS)
|
||||
])
|
Loading…
Reference in a new issue