[Thoggen-cvs] thoggen/src/gst-plugins .cvsignore,NONE,1.1 Makefile.am,NONE,1.1 th-deinterlace.c,NONE
Status: Beta
Brought to you by:
tp-m
Update of /cvsroot/thoggen/thoggen/src/gst-plugins In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1201 Added Files: .cvsignore Makefile.am th-deinterlace.c th-deinterlace.h th-dvdreadsrc.c th-dvdreadsrc.h th-videocrop.c th-videocrop.h Log Message: Put static plugins into their own directory; add th-deinterlace --- NEW FILE: .cvsignore --- Makefile Makefile.in thoggen .deps .libs .deps/ --- NEW FILE: Makefile.am --- noinst_LIBRARIES=libthoggenplugins.a SUFFIXES=.c SUBDIRS = INCLUDES = $(GSTREAMER_CFLAGS) EXTRA_DIST = libthoggenplugins_a_SOURCES = \ th-dvdreadsrc.c \ th-dvdreadsrc.h \ th-deinterlace.c \ th-deinterlace.h \ th-videocrop.c \ th-videocrop.h CLEANFILES = Makefile.am~ *.c~ *.h~ *.glade~ *.gladep *.gladep.bak clean-junk: rm -f *.c~ *.h~ *.glade~ *.gladep *.gladep.bak --- NEW FILE: th-deinterlace.h --- /* GStreamer * Copyright (C) <1999> Erik Walthinsen <om...@cs...> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __GST_DEINTERLACE_H__ #define __GST_DEINTERLACE_H__ #include <gst/gst.h> /* #include <gst/meta/audioraw.h> */ G_BEGIN_DECLS #define GST_TYPE_DEINTERLACE \ (th_deinterlace_get_type()) #define GST_DEINTERLACE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE,GstDeInterlace)) #define GST_DEINTERLACE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstDeInterlace)) #define GST_IS_DEINTERLACE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE)) #define GST_IS_DEINTERLACE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE)) typedef struct _GstDeInterlace GstDeInterlace; typedef struct _GstDeInterlaceClass GstDeInterlaceClass; struct _GstDeInterlace { GstElement element; GstPad *sinkpad, *srcpad; gint width, height; gboolean show_deinterlaced_area_only; gboolean blend; gint threshold_blend; /* here we start blending */ gint threshold; /* here we start interpolating TODO FIXME */ gint edge_detect; gint picsize; guchar *src; }; struct _GstDeInterlaceClass { GstElementClass parent_class; }; GType th_deinterlace_get_type (void); G_END_DECLS #endif /* __GST_DEINTERLACE_H__ */ --- NEW FILE: th-dvdreadsrc.c --- /*************************************************************************** th-dvdreadsrc.c --------------- begin : Wed Nov 17 2004 copyright : (C) 2004 by Tim-Philipp Müller copyright : (C) 2001 Thomas Östreich - June 2001 copyright : (C) 2001 Billy Biggs <ve...@du...> email : t....@or... ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*************************************************************************** * * * This is a from scratch re-implementation of dvdreadsrc, only that * * we don't support seeking and other fancy stuff, but only selecting * * a title and streaming out the bits and pieces for processing. * * (GStreamer's dvdreadsrc is just buggy in mysterious ways, and as * * we depend on libdvdread anyway, we can just as well ship our own * * dvd read plugin for the time being, instead of requiring people * * to install CVS HEAD gst-plugins (Nov 18, 2004). We can drop this * * once Gstreamer's dvdreadsrc is reasonably reliable and is shipped * * in the major distro releases. Currently, neither is the case. * * * * The DVD read code here is mostly nicked from transcode 0.6.3 * * * ***************************************************************************/ #include <stdlib.h> #include <string.h> #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "th-dvdreadsrc.h" #include <gst/gst.h> #include <dvdread/dvd_reader.h> #include <dvdread/ifo_types.h> #include <dvdread/ifo_read.h> #include <dvdread/nav_read.h> #define DEFAULT_LOCATION "/dev/dvd" enum { PROP_TITLE = 1, PROP_CHAPTER, PROP_ANGLE, PROP_LOCATION }; struct _ThDvdReadSrcPriv { gint titleid; /* title number, counting from 0 */ gint chapid; /* chapter number, counting from 0 */ gint angle; /* angle number, counting from 0 */ gchar *location; /* device */ gboolean file_open; gboolean need_seek; dvd_reader_t *dvd; dvd_file_t *dvd_title; ifo_handle_t *vmg_file; tt_srpt_t *tt_srpt; /* keep in function? only needed for _seek()? */ ifo_handle_t *vts_file; vts_ptt_srpt_t *vts_ptt_srpt; /* keep in function? */ pgc_t *cur_pgc; /* keep in function? */ gboolean in_pack_loop; gint cur_pack; gboolean in_cell_loop; gint start_cell; gint next_cell; gint last_cell; gint cur_cell; }; static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ( "src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY ); GST_DEBUG_CATEGORY_STATIC (dvd_read_src_debug); #define GST_CAT_DEFAULT dvd_read_src_debug /* Plugin stuff to have our custom * GstElement automatically * registered on program start-up */ static gboolean plugin_init (GstPlugin *plugin) { g_print ("registering static plugin thdvdreadsrc\n"); return gst_element_register (plugin, "thdvdreadsrc", GST_RANK_NONE, TH_TYPE_DVD_READ_SRC); } GST_PLUGIN_DEFINE_STATIC ( GST_VERSION_MAJOR, GST_VERSION_MINOR, "thdvdreadsrc", "ThDvdReadSrc", plugin_init, "0.1", "GPL", "Thoggen", "http://thoggen.net" ) static GstElementDetails dvd_read_src_details = GST_ELEMENT_DETAILS ( "DVD Title Source", "Source", "Just read a title from DVD for processing, no frills", "Tim-Philipp M\303\274ller <t....@or...>" ); #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (dvd_read_src_debug, "thdvdreadsrc", 0, "dvdreadsrc element"); GST_BOILERPLATE_FULL (ThDvdReadSrc, dvd_read_src, GstElement, GST_TYPE_ELEMENT, _do_init); static void dvd_read_src_finalize (GObject *obj); static void dvd_read_src_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void dvd_read_src_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static GstElementStateReturn dvd_read_src_change_state (GstElement *element); static GstData *dvd_read_src_get (GstPad *pad); static gboolean dvd_read_src_open_file (ThDvdReadSrc *src); static gboolean dvd_read_src_seek (ThDvdReadSrc *src); static void dvd_read_src_close_file (ThDvdReadSrc *src); /*************************************************************************** * * dvd_read_src_base_init * ***************************************************************************/ static void dvd_read_src_base_init (gpointer g_class) { GstElementClass *gstelement_class; GstPadTemplate *padtmpl; gstelement_class = GST_ELEMENT_CLASS (g_class); gst_element_class_set_details (gstelement_class, &dvd_read_src_details); padtmpl = gst_static_pad_template_get (&srctemplate); gst_element_class_add_pad_template (gstelement_class, padtmpl); } /*************************************************************************** * * dvd_read_src_class_init * ***************************************************************************/ static void dvd_read_src_class_init (ThDvdReadSrcClass *klass) { GstElementClass *gstelement_class; GObjectClass *gobject_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TITLE, g_param_spec_int ("title", "title", "Title (counting from 0)", 0, G_MAXINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHAPTER, g_param_spec_int ("chapter", "chapter", "Chapter (counting from 0)", 0, G_MAXINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE, g_param_spec_int ("angle", "angle", "Angle (counting from 0)", 0, G_MAXINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LOCATION, g_param_spec_string ("location", "location", "Device location (e.g. /dev/dvd)", DEFAULT_LOCATION, G_PARAM_READWRITE)); gobject_class->set_property = GST_DEBUG_FUNCPTR (dvd_read_src_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (dvd_read_src_get_property); gobject_class->finalize = GST_DEBUG_FUNCPTR (dvd_read_src_finalize); gstelement_class->change_state = GST_DEBUG_FUNCPTR (dvd_read_src_change_state); } /*************************************************************************** * * dvd_read_src_finalize * ***************************************************************************/ static void dvd_read_src_finalize (GObject *obj) { ThDvdReadSrc *src = (ThDvdReadSrc*) obj; g_free (src->priv->location); memset (src->priv, 0xab, sizeof (ThDvdReadSrcPriv)); g_free (src->priv); src->priv = NULL; } /*************************************************************************** * * dvd_read_src_init * ***************************************************************************/ static void dvd_read_src_init (ThDvdReadSrc *src) { GstPad *pad; src->priv = g_new0 (ThDvdReadSrcPriv, 1); /* create our output pad */ pad = gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), "src"); gst_element_add_pad (GST_ELEMENT (src), pad); gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (dvd_read_src_get)); src->priv->titleid = 0; src->priv->chapid = 0; src->priv->angle = 0; src->priv->file_open = FALSE; src->priv->need_seek = TRUE; } /*************************************************************************** * * dvd_read_src_set_property * ***************************************************************************/ static void dvd_read_src_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { ThDvdReadSrc *src = (ThDvdReadSrc*) obj; g_return_if_fail (TH_IS_DVD_READ_SRC (obj)); switch (prop_id) { case PROP_TITLE: src->priv->titleid = g_value_get_int (value); src->priv->need_seek = TRUE; break; case PROP_CHAPTER: src->priv->chapid = g_value_get_int (value); src->priv->need_seek = TRUE; break; case PROP_ANGLE: src->priv->angle = g_value_get_int (value); break; case PROP_LOCATION: { if (!src->priv->file_open) { g_free (src->priv->location); src->priv->location = g_value_dup_string (value); if (src->priv->location == NULL) src->priv->location = g_strdup (DEFAULT_LOCATION); } else { g_warning ("%s: Can't set device location while device is open!", G_STRLOC); } break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } /*************************************************************************** * * dvd_read_src_get_property * ***************************************************************************/ static void dvd_read_src_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { ThDvdReadSrc *src = (ThDvdReadSrc*) obj; g_return_if_fail (TH_IS_DVD_READ_SRC (obj)); switch (prop_id) { case PROP_TITLE: g_value_set_int (value, src->priv->titleid); break; case PROP_CHAPTER: g_value_set_int (value, src->priv->chapid); break; case PROP_ANGLE: g_value_set_int (value, src->priv->angle); break; case PROP_LOCATION: g_value_set_string (value, src->priv->location); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } /*************************************************************************** * * is_nav_pack * * Returns true if the pack is a NAV pack. This check is clearly * insufficient, and sometimes we incorrectly think that valid other * packs are NAV packs. Needs to be made stronger. * ***************************************************************************/ static gboolean is_nav_pack (const guint8 *buffer) { return (buffer[41] == 0xbf && buffer[1027] == 0xbf); } typedef enum { LOOP_DONE, LOOP_EOS, LOOP_ERROR, LOOP_GOT_BUFFER, LOOP_NEXT_ITERATION } DvdSrcLoopRet; /*************************************************************************** * * do_pack_loop_iteration * ***************************************************************************/ static DvdSrcLoopRet do_pack_loop_iteration (ThDvdReadSrc *src, GstBuffer *buf) { ThDvdReadSrcPriv *p; guint next_ilvu_start; guint cur_output_size; guint next_vobu, len; dsi_t dsi_pack; p = src->priv; /* Read NAV packet */ nav_retry: len = DVDReadBlocks (p->dvd_title, (int) p->cur_pack, 1, GST_BUFFER_DATA (buf)); if (len != 1) { GST_ERROR ("Read failed for block %d\n", p->cur_pack); dvd_read_src_close_file (src); return LOOP_ERROR; } if (!is_nav_pack (GST_BUFFER_DATA (buf))) { p->cur_pack++; goto nav_retry; } /* Parse the contained dsi packet */ navRead_DSI (&dsi_pack, ((guint8*)GST_BUFFER_DATA (buf)) + DSI_START_BYTE); if (!(p->cur_pack == dsi_pack.dsi_gi.nv_pck_lbn)) { cur_output_size = 0; dsi_pack.vobu_sri.next_vobu = SRI_END_OF_CELL; } /* Determine where we go next. These values are * the ones we mostly care about */ next_ilvu_start = p->cur_pack + dsi_pack.sml_agli.data[p->angle].address; cur_output_size = dsi_pack.dsi_gi.vobu_ea; /* If we're not at the end of this cell, we can determine the next * VOBU to display using the VOBU_SRI information section of the * DSI. Using this value correctly follows the current angle, * avoiding the doubled scenes in The Matrix, and makes our life * really happy. * * Otherwise, we set our next address past the end of this cell to * force the code above to go to the next cell in the program. */ if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) { next_vobu = p->cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff); } else { next_vobu = p->cur_pack + cur_output_size + 1; } g_assert (cur_output_size < 1024); p->cur_pack++; /* Read in and output cursize packs */ len = DVDReadBlocks (p->dvd_title, p->cur_pack, cur_output_size, GST_BUFFER_DATA (buf)); if ((gint) len != cur_output_size) { GST_ERROR ("Read failed for %d blocks at %d\n", cur_output_size, p->cur_pack); dvd_read_src_close_file (src); return LOOP_ERROR; } GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN; //fwrite (data, cur_output_size, DVD_VIDEO_LB_LEN, stdout); /* GST_LOG ("cur_pack = %d, cur_output_size = %d\n", p->cur_pack, cur_output_size); */ p->cur_pack = next_vobu; return LOOP_GOT_BUFFER; } /*************************************************************************** * * do_cell_loop_iteration * ***************************************************************************/ static DvdSrcLoopRet do_cell_loop_iteration (ThDvdReadSrc *src, GstBuffer *buf) { ThDvdReadSrcPriv *p = src->priv; if (p->in_pack_loop) goto pack_iteration; g_assert (p->next_cell < p->last_cell); p->cur_cell = p->next_cell; /* Check if we're entering an angle block */ if (p->cur_pgc->cell_playback[p->cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK) { int i; p->cur_cell += p->angle; for (i = 0;; ++i) { if (p->cur_pgc->cell_playback[p->cur_cell + i].block_mode == BLOCK_MODE_LAST_CELL) { p->next_cell = p->cur_cell + i + 1; break; } } } else { p->next_cell = p->cur_cell + 1; } p->cur_pack = p->cur_pgc->cell_playback[p->cur_cell].first_sector; p->in_pack_loop = TRUE; pack_iteration: /* We loop until we're out of the current cell */ if (p->cur_pack < p->cur_pgc->cell_playback[p->cur_cell].last_sector) { switch (do_pack_loop_iteration (src, buf)) { case LOOP_NEXT_ITERATION: case LOOP_DONE: case LOOP_EOS: g_assert_not_reached (); case LOOP_ERROR: return LOOP_ERROR; case LOOP_GOT_BUFFER: return LOOP_GOT_BUFFER; } } p->in_pack_loop = FALSE; return LOOP_NEXT_ITERATION; /* do next cell loop iteration */ } /*************************************************************************** * * dvd_read_src_get * ***************************************************************************/ static GstData * dvd_read_src_get (GstPad *pad) { DvdSrcLoopRet ret = -1; ThDvdReadSrc *src; GstBuffer *buf; g_return_val_if_fail (pad != NULL, NULL); src = (ThDvdReadSrc*) GST_OBJECT_PARENT (pad); g_return_val_if_fail (TH_IS_DVD_READ_SRC (src), NULL); g_return_val_if_fail (src->priv->file_open == TRUE, NULL); if (src->priv->need_seek) { if (!dvd_read_src_seek (src)) { GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), (NULL)); dvd_read_src_close_file (src); return NULL; } } buf = gst_buffer_new_and_alloc (1024 * DVD_VIDEO_LB_LEN); if (!src->priv->in_cell_loop) { src->priv->cur_cell = src->priv->start_cell; src->priv->next_cell = src->priv->start_cell; src->priv->in_cell_loop = TRUE; src->priv->in_pack_loop = FALSE; } do { /* EOS? */ if (src->priv->in_pack_loop == FALSE && src->priv->next_cell >= src->priv->last_cell) { gst_element_set_eos (GST_ELEMENT (src)); gst_buffer_unref (buf); return GST_DATA (gst_event_new (GST_EVENT_EOS)); } ret = do_cell_loop_iteration (src, buf); } while (ret == LOOP_NEXT_ITERATION); if (ret == LOOP_GOT_BUFFER) return GST_DATA (buf); GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), (NULL)); gst_buffer_unref (buf); dvd_read_src_close_file (src); g_return_val_if_fail (ret == LOOP_ERROR, NULL); return NULL; } /*************************************************************************** * * dvd_read_src_seek * * seeks to set title / chapter * ***************************************************************************/ static gboolean dvd_read_src_seek (ThDvdReadSrc *src) { ThDvdReadSrcPriv *p; gint pgn, ttn, pgc_id; p = src->priv; p->in_cell_loop = FALSE; /* Make sure our title number is valid */ GST_LOG ("There are %d titles on this DVD", p->tt_srpt->nr_of_srpts); if (p->titleid < 0 || p->titleid >= p->tt_srpt->nr_of_srpts) { GST_ERROR ("Invalid title %d", p->titleid + 1); dvd_read_src_close_file (src); return FALSE; } /* Make sure the chapter number is valid for this title */ GST_LOG ("There are %d chapters in this title", p->tt_srpt->title[p->titleid].nr_of_ptts); if (p->chapid < 0 || p->chapid >= p->tt_srpt->title[p->titleid].nr_of_ptts) { GST_ERROR ("Invalid title %d", p->chapid + 1); dvd_read_src_close_file (src); return FALSE; } /* Make sure the angle number is valid for this title */ GST_LOG ("There are %d angles available for this title", p->tt_srpt->title[p->titleid].nr_of_angles); if (p->angle < 0 || p->angle >= p->tt_srpt->title[p->titleid].nr_of_angles) { GST_ERROR ("Invalid angle %d", p->angle + 1); dvd_read_src_close_file (src); return FALSE; } /* Load the VTS information for the title set our title is in */ p->vts_file = ifoOpen (p->dvd, p->tt_srpt->title[p->titleid].title_set_nr); if (p->vts_file == NULL) { GST_ERROR ("Can't open the title %d info file", p->tt_srpt->title[p->titleid].title_set_nr); dvd_read_src_close_file (src); return FALSE; } /* Determine which program chain we want to * watch. This is based on the chapter number */ ttn = p->tt_srpt->title[p->titleid].vts_ttn; p->vts_ptt_srpt = p->vts_file->vts_ptt_srpt; pgc_id = p->vts_ptt_srpt->title[ttn - 1].ptt[p->chapid].pgcn; pgn = p->vts_ptt_srpt->title[ttn - 1].ptt[p->chapid].pgn; p->cur_pgc = p->vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc; p->start_cell = p->cur_pgc->program_map[pgn - 1] - 1; #if 0 /* ThOe */ if (p->chapid+1 == p->tt_srpt->title[p->titleid].nr_of_ptts) { p->last_cell = p->cur_pgc->nr_of_cells; } else { p->last_cell = p->cur_pgc->program_map[(p->vts_ptt_srpt->title[ttn - 1].ptt[p->chapid + 1].pgn) - 1] - 1; } #endif p->last_cell = p->cur_pgc->nr_of_cells; /* We've got enough info, time to open the title set data */ p->dvd_title = DVDOpenFile (p->dvd, p->tt_srpt->title[p->titleid].title_set_nr, DVD_READ_TITLE_VOBS); if (p->dvd_title == NULL) { GST_ERROR ("Can't open title VOBS (VTS_%02d_1.VOB).\n", p->tt_srpt->title[p->titleid].title_set_nr); dvd_read_src_close_file (src); return FALSE; } src->priv->need_seek = FALSE; return TRUE; } /*************************************************************************** * * dvd_read_src_open_file * ***************************************************************************/ static gboolean dvd_read_src_open_file (ThDvdReadSrc *src) { g_return_val_if_fail (src->priv->file_open == FALSE, FALSE); /* Open the disc */ src->priv->dvd = DVDOpen (src->priv->location); if (src->priv->dvd == NULL) { GST_ERROR ("Couldn't open DVD: %s", src->priv->location); GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), (NULL)); return FALSE; } /* Load the video manager to find out the * information about the titles on this disc */ src->priv->vmg_file = ifoOpen (src->priv->dvd, 0); if (src->priv->vmg_file == NULL) { GST_ERROR ("Can't open VMG info"); DVDClose (src->priv->dvd); GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), (NULL)); return FALSE; } src->priv->tt_srpt = src->priv->vmg_file->tt_srpt; if (!dvd_read_src_seek (src)) { GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), (NULL)); dvd_read_src_close_file (src); src->priv->tt_srpt = NULL; return FALSE; } src->priv->file_open = TRUE; src->priv->need_seek = TRUE; return TRUE; } /*************************************************************************** * * dvd_read_src_close_file * ***************************************************************************/ static void dvd_read_src_close_file (ThDvdReadSrc *src) { if (src->priv->vts_file) ifoClose (src->priv->vts_file); if (src->priv->vmg_file) ifoClose (src->priv->vmg_file); if (src->priv->dvd_title) DVDCloseFile (src->priv->dvd_title); if (src->priv->dvd) DVDClose (src->priv->dvd); src->priv->vts_file = NULL; src->priv->vmg_file = NULL; src->priv->dvd_title = NULL; src->priv->dvd = NULL; src->priv->tt_srpt = NULL; /* points into vmg_file struct */ src->priv->vts_ptt_srpt = NULL; /* points into vts_file struct */ src->priv->cur_pgc = NULL; /* points into vts_file struct */ src->priv->file_open = FALSE; src->priv->in_pack_loop = FALSE; src->priv->in_cell_loop = FALSE; src->priv->need_seek = TRUE; } /*************************************************************************** * * dvd_read_src_change_state * ***************************************************************************/ static GstElementStateReturn dvd_read_src_change_state (GstElement *element) { ThDvdReadSrc *src = (ThDvdReadSrc*) element; g_return_val_if_fail (TH_IS_DVD_READ_SRC (src), GST_STATE_FAILURE); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: { if (!dvd_read_src_open_file (src)) return GST_STATE_FAILURE; } break; case GST_STATE_READY_TO_PAUSED: case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PAUSED_TO_READY: break; case GST_STATE_READY_TO_NULL: dvd_read_src_close_file (src); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } --- NEW FILE: th-videocrop.h --- (This appears to be a binary file; contents omitted.) --- NEW FILE: th-videocrop.c --- (This appears to be a binary file; contents omitted.) --- NEW FILE: th-dvdreadsrc.h --- /*************************************************************************** th-dvdreadsrc.h --------------- begin : Wed Nov 17 2004 copyright : (C) 2004 by Tim-Philipp Müller email : t....@or... ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _th_dvd_read_src_h_included_ #define _th_dvd_read_src_h_included_ #include <gst/gstelement.h> #define TH_TYPE_DVD_READ_SRC (dvd_read_src_get_type()) #define TH_DVD_READ_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),TH_TYPE_DVD_READ_SRC,ThDvdReadSrc)) #define TH_DVD_READ_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),TH_TYPE_DVD_READ_SRC,ThDvdReadSrcClass)) #define TH_IS_DVD_READ_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),TH_TYPE_DVD_READ_SRC)) #define TH_IS_DVD_READ_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),TH_TYPE_DVD_READ_SRC)) typedef struct _ThDvdReadSrc ThDvdReadSrc; typedef struct _ThDvdReadSrcPriv ThDvdReadSrcPriv; typedef struct _ThDvdReadSrcClass ThDvdReadSrcClass; struct _ThDvdReadSrc { GstElement element; ThDvdReadSrcPriv *priv; }; struct _ThDvdReadSrcClass { GstElementClass parent_class; }; GType dvd_read_src_get_type (void) G_GNUC_CONST; #endif /* _th_dvd_read_src_h_included_ */ --- NEW FILE: th-deinterlace.c --- /* GStreamer * Copyright (C) <1999> Erik Walthinsen <om...@cs...> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* based on the Area Based Deinterlacer (for RGB frames) */ /* (a VirtualDub filter) from Gunnar Thalin <gu...@ho...> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include <gst/gst.h> #include <gst/video/video.h> #include "th-deinterlace.h" /* these macros are adapted from videocrop.c, paint_setup_I420() */ #define ROUND_UP_2(x) (((x)+1)&~1) #define ROUND_UP_4(x) (((x)+3)&~3) #define ROUND_UP_8(x) (((x)+7)&~7) #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (ROUND_UP_4(width)) #define GST_VIDEO_I420_U_ROWSTRIDE(width) (ROUND_UP_8(width)/2) #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2) #define GST_VIDEO_I420_Y_OFFSET(w,h) (0) #define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*ROUND_UP_2(h))) #define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*ROUND_UP_2(h)/2)) #define GST_VIDEO_I420_SIZE(w,h) (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*ROUND_UP_2(h)/2)) /* elementfactory information */ static GstElementDetails deinterlace_details = GST_ELEMENT_DETAILS ("Deinterlace", "Filter/Effect/Video", "Deinterlace video", "Wim Taymans <wim...@ch...>"); /* Filter signals and args */ enum { /* FILL ME */ LAST_SIGNAL }; enum { ARG_0, ARG_DI_ONLY, ARG_BLEND, ARG_THRESHOLD, ARG_EDGE_DETECT }; static GstStaticPadTemplate deinterlace_src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) ); static GstStaticPadTemplate deinterlace_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) ); static void gst_deinterlace_base_init (gpointer g_class); static void gst_deinterlace_class_init (GstDeInterlaceClass * klass); static void gst_deinterlace_init (GstDeInterlace * filter); static void gst_deinterlace_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_deinterlace_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_deinterlace_chain (GstPad * pad, GstData * _data); static GstElementClass *parent_class = NULL; /*static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; */ static GType gst_deinterlace_get_type (void) { static GType deinterlace_type = 0; if (!deinterlace_type) { static const GTypeInfo deinterlace_info = { sizeof (GstDeInterlaceClass), gst_deinterlace_base_init, NULL, (GClassInitFunc) gst_deinterlace_class_init, NULL, NULL, sizeof (GstDeInterlace), 0, (GInstanceInitFunc) gst_deinterlace_init, }; deinterlace_type = g_type_register_static (GST_TYPE_ELEMENT, "ThDeInterlace", &deinterlace_info, 0); } return deinterlace_type; } GType th_deinterlace_get_type (void) { return gst_deinterlace_get_type (); } static void gst_deinterlace_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&deinterlace_src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&deinterlace_sink_factory)); gst_element_class_set_details (element_class, &deinterlace_details); } static void gst_deinterlace_class_init (GstDeInterlaceClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; parent_class = g_type_class_ref (GST_TYPE_ELEMENT); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DI_ONLY, g_param_spec_boolean ("di_area_only", "di_area_only", "di_area_only", TRUE, G_PARAM_READWRITE)); /* CHECKME */ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLEND, g_param_spec_boolean ("blend", "blend", "blend", TRUE, G_PARAM_READWRITE)); /* CHECKME */ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_THRESHOLD, g_param_spec_int ("threshold", "threshold", "threshold", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); /* CHECKME */ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EDGE_DETECT, g_param_spec_int ("edge_detect", "edge_detect", "edge_detect", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); /* CHECKME */ gobject_class->set_property = gst_deinterlace_set_property; gobject_class->get_property = gst_deinterlace_get_property; } static GstCaps * gst_deinterlace_getcaps (GstPad * pad) { GstDeInterlace *filter; GstPad *otherpad; filter = GST_DEINTERLACE (gst_pad_get_parent (pad)); otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; return gst_pad_get_allowed_caps (otherpad); } static GstPadLinkReturn gst_deinterlace_link (GstPad * pad, const GstCaps * caps) { GstDeInterlace *filter; GstStructure *structure; GstPadLinkReturn ret; GstPad *otherpad; filter = GST_DEINTERLACE (gst_pad_get_parent (pad)); otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; ret = gst_pad_try_set_caps (otherpad, caps); if (GST_PAD_LINK_FAILED (ret)) { return ret; } structure = gst_caps_get_structure (caps, 0); gst_structure_get_int (structure, "width", &filter->width); gst_structure_get_int (structure, "height", &filter->height); if (filter->picsize != GST_VIDEO_I420_SIZE (filter->width, filter->height)) { if (filter->src) g_free (filter->src); filter->picsize = GST_VIDEO_I420_SIZE (filter->width, filter->height); filter->src = g_malloc (filter->picsize); } return GST_PAD_LINK_OK; } static void gst_deinterlace_init (GstDeInterlace * filter) { filter->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&deinterlace_sink_factory), "sink"); gst_pad_set_chain_function (filter->sinkpad, gst_deinterlace_chain); gst_pad_set_link_function (filter->sinkpad, gst_deinterlace_link); gst_pad_set_getcaps_function (filter->sinkpad, gst_deinterlace_getcaps); gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); filter->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&deinterlace_src_factory), "src"); gst_pad_set_link_function (filter->srcpad, gst_deinterlace_link); gst_pad_set_getcaps_function (filter->srcpad, gst_deinterlace_getcaps); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); filter->show_deinterlaced_area_only = FALSE; filter->blend = FALSE; /*filter->threshold_blend = 0; */ filter->threshold = 50; filter->edge_detect = 25; filter->src = NULL; filter->picsize = 0; } static void gst_deinterlace_chain (GstPad * pad, GstData * _data) { GstBuffer *buf = GST_BUFFER (_data); GstDeInterlace *filter; gint y0, y1, y2, y3; guchar *psrc1, *psrc2, *psrc3, *pdst1, *yuvptr, *src; gint iInterlaceValue0, iInterlaceValue1, iInterlaceValue2; gint x, y; gint y_line; guchar *y_dst, *y_src; gboolean bBlend; gint iThreshold; gint iEdgeDetect; gint width, height; gboolean bShowDeinterlacedAreaOnly; g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); filter = GST_DEINTERLACE (gst_pad_get_parent (pad)); bBlend = filter->blend; iThreshold = filter->threshold; iEdgeDetect = filter->edge_detect; width = filter->width; height = filter->height; src = filter->src; yuvptr = GST_BUFFER_DATA (buf); bShowDeinterlacedAreaOnly = filter->show_deinterlaced_area_only; if (filter->picsize < GST_BUFFER_SIZE (buf)) { GST_ERROR ("thdeinterlace: size of incoming buffer is bigger than expected size (%u bytes, %ux%u, expected: %u bytes)\n", (guint) GST_BUFFER_SIZE (buf), width, height, filter->picsize); return; } memcpy (filter->src, yuvptr, filter->picsize); y_dst = yuvptr; /* dst y pointer */ /* we should not change u,v because one u, v value stands for */ /* 2 pixels per 2 lines = 4 pixel and we don't want to change */ /* the color of */ y_line = width; y_src = src; iThreshold = iThreshold * iThreshold * 4; /* We don't want an integer overflow in the interlace calculation. */ if (iEdgeDetect > 180) iEdgeDetect = 180; iEdgeDetect = iEdgeDetect * iEdgeDetect; y1 = 0; /* Avoid compiler warning. The value is not used. */ for (x = 0; x < width; x++) { psrc3 = y_src + x; y3 = *psrc3; psrc2 = psrc3 + y_line; y2 = *psrc2; pdst1 = y_dst + x; iInterlaceValue1 = iInterlaceValue2 = 0; for (y = 0; y <= height; y++) { psrc1 = psrc2; psrc2 = psrc3; psrc3 = psrc3 + y_line; y0 = y1; y1 = y2; y2 = y3; if (y < height - 1) { y3 = *psrc3; } else { y3 = y1; } iInterlaceValue0 = iInterlaceValue1; iInterlaceValue1 = iInterlaceValue2; if (y < height) iInterlaceValue2 = ((y1 - y2) * (y3 - y2) - ((iEdgeDetect * (y1 - y3) * (y1 - y3)) >> 12)) * 10; else iInterlaceValue2 = 0; if (y > 0) { if (iInterlaceValue0 + 2 * iInterlaceValue1 + iInterlaceValue2 > iThreshold) { if (bBlend) { *pdst1 = (unsigned char) ((y0 + 2 * y1 + y2) >> 2); } else { /* this method seems to work better than blending if the */ /* quality is pretty bad and the half pics don't fit together */ if ((y % 2) == 1) { /* if odd simply copy the value */ *pdst1 = *psrc1; /**pdst1 = 0; // FIXME this is for adjusting an initial iThreshold */ } else { /* even interpolate the even line (upper + lower)/2 */ *pdst1 = (unsigned char) ((y0 + y2) >> 1); /**pdst1 = 0; // FIXME this is for adjusting an initial iThreshold */ } } } else { /* so we went below the treshold and therefore we don't have to */ /* change anything */ if (bShowDeinterlacedAreaOnly) { /* this is for testing to see how we should tune the treshhold */ /* and shows as the things that haven't change because the */ /* threshhold was to low?? (or shows that everything is ok :-) */ *pdst1 = 0; /* blank the point and so the interlac area */ } else { *pdst1 = *psrc1; } } pdst1 = pdst1 + y_line; } } } gst_pad_push (filter->srcpad, GST_DATA (buf)); } static void gst_deinterlace_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstDeInterlace *filter; /* it's not null if we got it, but it might not be ours */ g_return_if_fail (GST_IS_DEINTERLACE (object)); filter = GST_DEINTERLACE (object); switch (prop_id) { case ARG_DI_ONLY: filter->show_deinterlaced_area_only = g_value_get_boolean (value); break; case ARG_BLEND: filter->blend = g_value_get_boolean (value); break; case ARG_THRESHOLD: filter->threshold = g_value_get_int (value); break; case ARG_EDGE_DETECT: filter->edge_detect = g_value_get_int (value); break; default: break; } } static void gst_deinterlace_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstDeInterlace *filter; /* it's not null if we got it, but it might not be ours */ g_return_if_fail (GST_IS_DEINTERLACE (object)); filter = GST_DEINTERLACE (object); switch (prop_id) { case ARG_DI_ONLY: g_value_set_boolean (value, filter->show_deinterlaced_area_only); break; case ARG_BLEND: g_value_set_boolean (value, filter->blend); break; case ARG_THRESHOLD: g_value_set_int (value, filter->threshold); break; case ARG_EDGE_DETECT: g_value_set_int (value, filter->edge_detect); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean plugin_init (GstPlugin * plugin) { g_print ("registering static plugin thdeinterlace\n"); return gst_element_register (plugin, "thdeinterlace", GST_RANK_NONE, gst_deinterlace_get_type ()); } GST_PLUGIN_DEFINE_STATIC ( GST_VERSION_MAJOR, GST_VERSION_MINOR, "thdeinterlace", "Deinterlace video", plugin_init, VERSION, "LGPL", PACKAGE, "http://thoggen.net" ) |