mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
sys/dvb/: Integrate SoC work done by Alessandro for the Freevo project.
Original commit message from CVS: patch by: Alessandro Decina * sys/dvb/Makefile.am: * sys/dvb/cam.c: * sys/dvb/cam.h: * sys/dvb/camapplication.c: * sys/dvb/camapplication.h: * sys/dvb/camapplicationinfo.c: * sys/dvb/camapplicationinfo.h: * sys/dvb/camconditionalaccess.c: * sys/dvb/camconditionalaccess.h: * sys/dvb/camdevice.c: * sys/dvb/camdevice.h: * sys/dvb/camresourcemanager.c: * sys/dvb/camresourcemanager.h: * sys/dvb/camsession.c: * sys/dvb/camsession.h: * sys/dvb/camswclient.c: * sys/dvb/camswclient.h: * sys/dvb/camtransport.c: * sys/dvb/camtransport.h: * sys/dvb/camutils.c: * sys/dvb/camutils.h: * sys/dvb/dvbbasebin.c: * sys/dvb/dvbbasebin.h: * sys/dvb/gstdvb.c: * sys/dvb/gstdvbsrc.c: * sys/dvb/gstdvbsrc.h: Integrate SoC work done by Alessandro for the Freevo project. Adds cam support to the dvb stack in GStreamer and a new element (actually a bin) called dvbbasebin that integrates dvbsrc and mpegtsparse to a) handle decryption and b) allow acquiring multiple channels on same transponder without knowing pid numbers.
This commit is contained in:
parent
389904f624
commit
c205b740d4
27 changed files with 4520 additions and 74 deletions
37
ChangeLog
37
ChangeLog
|
@ -1,3 +1,40 @@
|
|||
2007-10-16 Zaheer Abbas Merali <zaheerabbas at merali dot org>
|
||||
|
||||
patch by: Alessandro Decina
|
||||
|
||||
* sys/dvb/Makefile.am:
|
||||
* sys/dvb/cam.c:
|
||||
* sys/dvb/cam.h:
|
||||
* sys/dvb/camapplication.c:
|
||||
* sys/dvb/camapplication.h:
|
||||
* sys/dvb/camapplicationinfo.c:
|
||||
* sys/dvb/camapplicationinfo.h:
|
||||
* sys/dvb/camconditionalaccess.c:
|
||||
* sys/dvb/camconditionalaccess.h:
|
||||
* sys/dvb/camdevice.c:
|
||||
* sys/dvb/camdevice.h:
|
||||
* sys/dvb/camresourcemanager.c:
|
||||
* sys/dvb/camresourcemanager.h:
|
||||
* sys/dvb/camsession.c:
|
||||
* sys/dvb/camsession.h:
|
||||
* sys/dvb/camswclient.c:
|
||||
* sys/dvb/camswclient.h:
|
||||
* sys/dvb/camtransport.c:
|
||||
* sys/dvb/camtransport.h:
|
||||
* sys/dvb/camutils.c:
|
||||
* sys/dvb/camutils.h:
|
||||
* sys/dvb/dvbbasebin.c:
|
||||
* sys/dvb/dvbbasebin.h:
|
||||
* sys/dvb/gstdvb.c:
|
||||
* sys/dvb/gstdvbsrc.c:
|
||||
* sys/dvb/gstdvbsrc.h:
|
||||
Integrate SoC work done by Alessandro for the Freevo project.
|
||||
Adds cam support to the dvb stack in GStreamer and a new
|
||||
element (actually a bin) called dvbbasebin that integrates
|
||||
dvbsrc and mpegtsparse to a) handle decryption and b) allow
|
||||
acquiring multiple channels on same transponder without
|
||||
knowing pid numbers.
|
||||
|
||||
2007-10-16 Zaheer Abbas Merali <zaheerabbas at merali dot org>
|
||||
|
||||
patch by: Alessandro Decina
|
||||
|
|
|
@ -1,9 +1,36 @@
|
|||
|
||||
plugin_LTLIBRARIES = libgstdvbsrc.la
|
||||
plugin_LTLIBRARIES = libgstdvb.la
|
||||
|
||||
libgstdvbsrc_la_SOURCES = gstdvbsrc.c
|
||||
libgstdvbsrc_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstdvbsrc_la_LIBADD = $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
|
||||
libgstdvbsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstdvb_la_SOURCES = \
|
||||
gstdvb.c \
|
||||
gstdvbsrc.c \
|
||||
dvbbasebin.c \
|
||||
cam.c \
|
||||
camdevice.c \
|
||||
camswclient.c \
|
||||
camutils.c \
|
||||
camtransport.c \
|
||||
camsession.c \
|
||||
camapplication.c \
|
||||
camresourcemanager.c \
|
||||
camapplicationinfo.c \
|
||||
camconditionalaccess.c
|
||||
|
||||
noinst_HEADERS = gstdvbsrc.h
|
||||
libgstdvb_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstdvb_la_LIBADD = $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
|
||||
libgstdvb_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstdvbsrc.h \
|
||||
dvbbasebin.h \
|
||||
cam.h \
|
||||
camdevice.h \
|
||||
camswclient.h \
|
||||
camutils.h \
|
||||
camtransport.h \
|
||||
camsession.h \
|
||||
camapplication.h \
|
||||
camresourcemanager.h \
|
||||
camapplicationinfo.h \
|
||||
camconditionalaccess.h
|
||||
|
||||
|
|
33
sys/dvb/cam.c
Normal file
33
sys/dvb/cam.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* cam.c -
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "cam.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
GST_DEBUG_CATEGORY (cam_debug_cat);
|
||||
|
||||
void
|
||||
cam_init ()
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (cam_debug_cat, "dvbcam", 0, "DVB CAM support");
|
||||
}
|
33
sys/dvb/cam.h
Normal file
33
sys/dvb/cam.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* cam.h -
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_H
|
||||
#define CAM_H
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (cam_debug_cat);
|
||||
|
||||
void cam_init ();
|
||||
|
||||
#endif /* CAM_H */
|
292
sys/dvb/camapplication.c
Normal file
292
sys/dvb/camapplication.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* camapplication.c - GStreamer CAM (EN50221) Application Layer
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "camapplication.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
|
||||
static CamReturn open_session_request_cb (CamSL * sl,
|
||||
CamSLSession * session, CamSLResourceStatus * status);
|
||||
static CamReturn session_opened_cb (CamSL * sl, CamSLSession * session);
|
||||
static CamReturn session_closed_cb (CamSL * sl, CamSLSession * session);
|
||||
static CamReturn session_data_cb (CamSL * sl,
|
||||
CamSLSession * session, guint8 * data, guint length);
|
||||
|
||||
static guint
|
||||
resource_id_hash (gconstpointer key)
|
||||
{
|
||||
guint resource_id = (guint) key;
|
||||
|
||||
if (!CAM_AL_RESOURCE_ID_IS_PUBLIC (resource_id)) {
|
||||
/* private identifier, leave it as is */
|
||||
return resource_id;
|
||||
}
|
||||
|
||||
/* public identifier, mask out the version number */
|
||||
return resource_id >> 6;
|
||||
}
|
||||
|
||||
CamAL *
|
||||
cam_al_new (CamSL * sl)
|
||||
{
|
||||
CamAL *al = g_new0 (CamAL, 1);
|
||||
|
||||
al->sl = sl;
|
||||
al->applications = g_hash_table_new (resource_id_hash, g_direct_equal);
|
||||
|
||||
sl->user_data = al;
|
||||
sl->open_session_request = open_session_request_cb;
|
||||
sl->session_opened = session_opened_cb;
|
||||
sl->session_closed = session_closed_cb;
|
||||
sl->session_data = session_data_cb;
|
||||
|
||||
return al;
|
||||
}
|
||||
|
||||
void
|
||||
cam_al_destroy (CamAL * al)
|
||||
{
|
||||
g_hash_table_destroy (al->applications);
|
||||
g_free (al);
|
||||
}
|
||||
|
||||
gboolean
|
||||
cam_al_install (CamAL * al, CamALApplication * application)
|
||||
{
|
||||
if (g_hash_table_lookup (al->applications,
|
||||
GINT_TO_POINTER (application->resource_id)) != NULL)
|
||||
return FALSE;
|
||||
|
||||
application->al = al;
|
||||
|
||||
g_hash_table_insert (al->applications,
|
||||
GINT_TO_POINTER (application->resource_id), application);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cam_al_uninstall (CamAL * al, CamALApplication * application)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = g_hash_table_remove (al->applications,
|
||||
GINT_TO_POINTER (application->resource_id));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CamALApplication *
|
||||
cam_al_get (CamAL * al, guint resource_id)
|
||||
{
|
||||
return CAM_AL_APPLICATION (g_hash_table_lookup (al->applications,
|
||||
GINT_TO_POINTER (resource_id)));
|
||||
}
|
||||
|
||||
void
|
||||
_cam_al_application_init (CamALApplication * application)
|
||||
{
|
||||
application->sessions = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_cam_al_application_destroy (CamALApplication * application)
|
||||
{
|
||||
g_list_free (application->sessions);
|
||||
}
|
||||
|
||||
static void
|
||||
foreach_get_key (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
GList **lst = (GList **) user_data;
|
||||
|
||||
*lst = g_list_append (*lst, key);
|
||||
}
|
||||
|
||||
GList *
|
||||
cam_al_get_resource_ids (CamAL * al)
|
||||
{
|
||||
GList *resource_ids = NULL;
|
||||
|
||||
g_hash_table_foreach (al->applications, foreach_get_key, &resource_ids);
|
||||
|
||||
return resource_ids;
|
||||
}
|
||||
|
||||
void
|
||||
cam_al_calc_buffer_size (CamAL * al, guint body_length,
|
||||
guint * buffer_size, guint * offset)
|
||||
{
|
||||
guint apdu_header_length;
|
||||
guint8 length_field_len;
|
||||
|
||||
/* get the length of the lenght_field() */
|
||||
length_field_len = cam_calc_length_field_size (body_length);
|
||||
|
||||
/* sum the APDU header */
|
||||
apdu_header_length = 3 + length_field_len;
|
||||
|
||||
/* chain up to the session layer to get the size of the buffer that can
|
||||
* contain the whole APDU */
|
||||
cam_sl_calc_buffer_size (al->sl, apdu_header_length + body_length,
|
||||
buffer_size, offset);
|
||||
|
||||
/* add the APDU header to the SPDU offset */
|
||||
*offset += apdu_header_length;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_al_application_write (CamALApplication * application,
|
||||
CamSLSession * session, guint tag, guint8 * buffer, guint buffer_size,
|
||||
guint body_length)
|
||||
{
|
||||
guint length_field_len;
|
||||
guint apdu_header_length;
|
||||
guint8 *apdu;
|
||||
|
||||
length_field_len = cam_calc_length_field_size (body_length);
|
||||
apdu_header_length = 3 + length_field_len;
|
||||
apdu = (buffer + buffer_size) - body_length - apdu_header_length;
|
||||
apdu[0] = tag >> 16;
|
||||
apdu[1] = (tag >> 8) & 0xFF;
|
||||
apdu[2] = tag & 0xFF;
|
||||
|
||||
cam_write_length_field (&apdu[3], body_length);
|
||||
|
||||
return cam_sl_session_write (session, buffer, buffer_size,
|
||||
apdu_header_length + body_length);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
open_session_request_cb (CamSL * sl, CamSLSession * session,
|
||||
CamSLResourceStatus * status)
|
||||
{
|
||||
CamAL *al = CAM_AL (sl->user_data);
|
||||
CamALApplication *application;
|
||||
guint resource_id = session->resource_id;
|
||||
CamReturn ret;
|
||||
|
||||
application = g_hash_table_lookup (al->applications,
|
||||
GINT_TO_POINTER (resource_id));
|
||||
if (application == NULL) {
|
||||
*status = CAM_SL_RESOURCE_STATUS_NOT_FOUND;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
if (CAM_AL_RESOURCE_ID_VERSION (application->resource_id)
|
||||
< CAM_AL_RESOURCE_ID_VERSION (resource_id)) {
|
||||
*status = CAM_SL_RESOURCE_STATUS_INVALID_VERSION;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
ret = application->session_request (application, session, status);
|
||||
if (CAM_FAILED (ret)) {
|
||||
*status = CAM_SL_RESOURCE_STATUS_NOT_FOUND;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (*status == CAM_SL_RESOURCE_STATUS_OPEN) {
|
||||
session->user_data = application;
|
||||
application->sessions = g_list_append (application->sessions, session);
|
||||
}
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
session_opened_cb (CamSL * sl, CamSLSession * session)
|
||||
{
|
||||
CamALApplication *application;
|
||||
|
||||
application = CAM_AL_APPLICATION (session->user_data);
|
||||
if (application == NULL) {
|
||||
GST_ERROR ("session is established but has no application");
|
||||
return CAM_RETURN_APPLICATION_ERROR;
|
||||
}
|
||||
|
||||
return application->open (application, session);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
session_closed_cb (CamSL * sl, CamSLSession * session)
|
||||
{
|
||||
CamALApplication *application;
|
||||
CamReturn ret;
|
||||
GList *walk;
|
||||
|
||||
application = CAM_AL_APPLICATION (session->user_data);
|
||||
if (application == NULL) {
|
||||
GST_ERROR ("session is established but has no application");
|
||||
return CAM_RETURN_APPLICATION_ERROR;
|
||||
}
|
||||
|
||||
ret = application->close (application, session);
|
||||
for (walk = application->sessions; walk; walk = g_list_next (walk)) {
|
||||
CamSLSession *s = CAM_SL_SESSION (walk->data);
|
||||
|
||||
if (s->session_nb == session->session_nb) {
|
||||
application->sessions = g_list_delete_link (application->sessions, walk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
session_data_cb (CamSL * sl, CamSLSession * session, guint8 * data, guint size)
|
||||
{
|
||||
CamALApplication *application;
|
||||
guint tag = 0;
|
||||
guint8 length_field_len;
|
||||
guint length;
|
||||
guint i;
|
||||
|
||||
application = CAM_AL_APPLICATION (session->user_data);
|
||||
if (application == NULL) {
|
||||
GST_ERROR ("session is established but has no application");
|
||||
return CAM_RETURN_APPLICATION_ERROR;
|
||||
}
|
||||
|
||||
if (size < 4) {
|
||||
GST_ERROR ("invalid APDU length %d", size);
|
||||
return CAM_RETURN_APPLICATION_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; ++i)
|
||||
tag = (tag << 8) | data[i];
|
||||
|
||||
length_field_len = cam_read_length_field (&data[3], &length);
|
||||
|
||||
if (length != size - 4) {
|
||||
GST_ERROR ("unexpected APDU length %d expected %d", length, size);
|
||||
|
||||
return CAM_RETURN_APPLICATION_ERROR;
|
||||
}
|
||||
|
||||
return application->data (application, session,
|
||||
tag, data + 3 + length_field_len, length);
|
||||
}
|
84
sys/dvb/camapplication.h
Normal file
84
sys/dvb/camapplication.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* camapplication.h - GStreamer CAM (EN50221) Application Layer
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_APPLICATION_LAYER_H
|
||||
#define CAM_APPLICATION_LAYER_H
|
||||
|
||||
#include "cam.h"
|
||||
#include "camsession.h"
|
||||
|
||||
#define CAM_AL(obj) ((CamAL *) obj)
|
||||
#define CAM_AL_APPLICATION(obj) ((CamALApplication *) obj)
|
||||
|
||||
#define CAM_AL_RESOURCE_ID_IS_PUBLIC(resource_id) ((resource_id >> 30) != 3)
|
||||
#define CAM_AL_RESOURCE_ID_CLASS(resource_id) ((resource_id >> 16) & 0x3FFF)
|
||||
#define CAM_AL_RESOURCE_ID_TYPE(resource_id) ((resource_id >> 6) & 0x03FF)
|
||||
#define CAM_AL_RESOURCE_ID_VERSION(resource_id) (resource_id & 0x3F)
|
||||
|
||||
#define CAM_AL_RESOURCE_MANAGER_ID 0x10041
|
||||
#define CAM_AL_APPLICATION_INFO_ID 0x20041
|
||||
#define CAM_AL_CONDITIONAL_ACCESS_ID 0x30041
|
||||
|
||||
typedef struct _CamAL CamAL;
|
||||
typedef struct _CamALApplication CamALApplication;
|
||||
|
||||
struct _CamAL
|
||||
{
|
||||
CamSL *sl;
|
||||
|
||||
GHashTable *applications;
|
||||
};
|
||||
|
||||
struct _CamALApplication
|
||||
{
|
||||
CamAL *al;
|
||||
guint resource_id;
|
||||
GList *sessions;
|
||||
|
||||
/* vtable */
|
||||
CamReturn (*session_request) (CamALApplication *application,
|
||||
CamSLSession *session, CamSLResourceStatus *status);
|
||||
CamReturn (*open) (CamALApplication *application, CamSLSession *session);
|
||||
CamReturn (*close) (CamALApplication *application, CamSLSession *session);
|
||||
CamReturn (*data) (CamALApplication *application, CamSLSession *session,
|
||||
guint tag, guint8 *buffer, guint length);
|
||||
};
|
||||
|
||||
CamAL *cam_al_new (CamSL *sl);
|
||||
void cam_al_destroy (CamAL *al);
|
||||
|
||||
gboolean cam_al_install (CamAL *al, CamALApplication *application);
|
||||
gboolean cam_al_uninstall (CamAL *al, CamALApplication *application);
|
||||
CamALApplication *cam_al_get (CamAL *al, guint resource_id);
|
||||
GList *cam_al_get_resource_ids (CamAL *al);
|
||||
|
||||
void cam_al_calc_buffer_size (CamAL *al, guint body_length,
|
||||
guint *buffer_size, guint *offset);
|
||||
|
||||
void _cam_al_application_init (CamALApplication *application);
|
||||
void _cam_al_application_destroy (CamALApplication *application);
|
||||
|
||||
CamReturn cam_al_application_write (CamALApplication *application,
|
||||
CamSLSession *session, guint tag, guint8 *buffer,
|
||||
guint buffer_size, guint body_length);
|
||||
#endif /* CAM_APPLICATION_LAYER_H */
|
153
sys/dvb/camapplicationinfo.c
Normal file
153
sys/dvb/camapplicationinfo.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* camapplicationinfo.h - CAM (EN50221) Application Info resource
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "camapplicationinfo.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
#define TAG_APPLICATION_INFO_ENQUIRY 0x9F8020
|
||||
#define TAG_APPLICATION_INFO_REPLY 0x9F8021
|
||||
#define TAG_APPLICATION_INFO_ENTER_MENU 0x9F8022
|
||||
|
||||
static CamReturn session_request_impl (CamALApplication * application,
|
||||
CamSLSession * session, CamSLResourceStatus * status);
|
||||
static CamReturn open_impl (CamALApplication * application,
|
||||
CamSLSession * session);
|
||||
static CamReturn close_impl (CamALApplication * application,
|
||||
CamSLSession * session);
|
||||
static CamReturn data_impl (CamALApplication * application,
|
||||
CamSLSession * session, guint tag, guint8 * buffer, guint length);
|
||||
|
||||
CamApplicationInfo *
|
||||
cam_application_info_new ()
|
||||
{
|
||||
CamApplicationInfo *info;
|
||||
CamALApplication *application;
|
||||
|
||||
info = g_new0 (CamApplicationInfo, 1);
|
||||
application = CAM_AL_APPLICATION (info);
|
||||
_cam_al_application_init (application);
|
||||
application->resource_id = CAM_AL_APPLICATION_INFO_ID;
|
||||
application->session_request = session_request_impl;
|
||||
application->open = open_impl;
|
||||
application->close = close_impl;
|
||||
application->data = data_impl;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
cam_application_info_destroy (CamApplicationInfo * info)
|
||||
{
|
||||
_cam_al_application_destroy (CAM_AL_APPLICATION (info));
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_simple (CamApplicationInfo * info, CamSLSession * session, guint tag)
|
||||
{
|
||||
guint8 *buffer;
|
||||
guint offset;
|
||||
guint buffer_size;
|
||||
CamReturn ret;
|
||||
|
||||
cam_al_calc_buffer_size (CAM_AL_APPLICATION (info)->al, 0, &buffer_size,
|
||||
&offset);
|
||||
buffer = g_malloc (buffer_size);
|
||||
|
||||
ret = cam_al_application_write (CAM_AL_APPLICATION (info), session,
|
||||
tag, buffer, buffer_size, 0);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_application_info_enquiry (CamApplicationInfo * info,
|
||||
CamSLSession * session)
|
||||
{
|
||||
GST_DEBUG ("sending application info enquiry");
|
||||
return send_simple (info, session, TAG_APPLICATION_INFO_ENQUIRY);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
session_request_impl (CamALApplication * application,
|
||||
CamSLSession * session, CamSLResourceStatus * status)
|
||||
{
|
||||
*status = CAM_SL_RESOURCE_STATUS_OPEN;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
open_impl (CamALApplication * application, CamSLSession * session)
|
||||
{
|
||||
CamApplicationInfo *info = CAM_APPLICATION_INFO (application);
|
||||
|
||||
return send_application_info_enquiry (info, session);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
close_impl (CamALApplication * application, CamSLSession * session)
|
||||
{
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_application_info_reply (CamApplicationInfo * info,
|
||||
CamSLSession * session, guint8 * buffer, guint length)
|
||||
{
|
||||
guint8 type;
|
||||
guint8 menu_length;
|
||||
gchar menu[255];
|
||||
|
||||
type = buffer[0];
|
||||
menu_length = buffer[5];
|
||||
menu_length = MIN (menu_length, 255);
|
||||
memcpy (menu, buffer + 6, menu_length);
|
||||
menu[menu_length] = 0;
|
||||
|
||||
GST_INFO ("application info reply, type: %d, menu: %s", type, menu);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
data_impl (CamALApplication * application, CamSLSession * session,
|
||||
guint tag, guint8 * buffer, guint length)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamApplicationInfo *info = CAM_APPLICATION_INFO (application);
|
||||
|
||||
switch (tag) {
|
||||
case TAG_APPLICATION_INFO_REPLY:
|
||||
ret = handle_application_info_reply (info, session, buffer, length);
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (CAM_RETURN_ERROR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
41
sys/dvb/camapplicationinfo.h
Normal file
41
sys/dvb/camapplicationinfo.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* camapplicationinfo.h - CAM (EN50221) Application Info resource
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_APPLICATION_INFO_H
|
||||
#define CAM_APPLICATION_INFO_H
|
||||
|
||||
#include "camapplication.h"
|
||||
|
||||
#define CAM_APPLICATION_INFO(obj) ((CamApplicationInfo *) obj)
|
||||
|
||||
typedef struct _CamApplicationInfo CamApplicationInfo;
|
||||
|
||||
struct _CamApplicationInfo
|
||||
{
|
||||
CamALApplication application;
|
||||
};
|
||||
|
||||
CamApplicationInfo *cam_application_info_new ();
|
||||
void cam_application_info_destroy (CamApplicationInfo *info);
|
||||
|
||||
#endif /* CAM_APPLICATION_INFO_H */
|
208
sys/dvb/camconditionalaccess.c
Normal file
208
sys/dvb/camconditionalaccess.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* camconditionalaccess.c - CAM (EN50221) Conditional Access resource
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "camutils.h"
|
||||
#include "camconditionalaccess.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
#define TAG_CONDITIONAL_ACCESS_INFO_ENQUIRY 0x9F8030
|
||||
#define TAG_CONDITIONAL_ACCESS_INFO_REPLY 0x9F8031
|
||||
#define TAG_CONDITIONAL_ACCESS_PMT 0x9F8032
|
||||
|
||||
static CamReturn session_request_impl (CamALApplication * application,
|
||||
CamSLSession * session, CamSLResourceStatus * status);
|
||||
static CamReturn open_impl (CamALApplication * application,
|
||||
CamSLSession * session);
|
||||
static CamReturn close_impl (CamALApplication * application,
|
||||
CamSLSession * session);
|
||||
static CamReturn data_impl (CamALApplication * application,
|
||||
CamSLSession * session, guint tag, guint8 * buffer, guint length);
|
||||
|
||||
CamConditionalAccess *
|
||||
cam_conditional_access_new ()
|
||||
{
|
||||
CamConditionalAccess *cas;
|
||||
CamALApplication *application;
|
||||
|
||||
cas = g_new0 (CamConditionalAccess, 1);
|
||||
|
||||
application = CAM_AL_APPLICATION (cas);
|
||||
_cam_al_application_init (application);
|
||||
application->resource_id = CAM_AL_CONDITIONAL_ACCESS_ID;
|
||||
application->session_request = session_request_impl;
|
||||
application->open = open_impl;
|
||||
application->close = close_impl;
|
||||
application->data = data_impl;
|
||||
|
||||
cas->ready = FALSE;
|
||||
|
||||
return cas;
|
||||
}
|
||||
|
||||
void
|
||||
cam_conditional_access_destroy (CamConditionalAccess * cas)
|
||||
{
|
||||
_cam_al_application_destroy (CAM_AL_APPLICATION (cas));
|
||||
g_free (cas);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_ca_pmt (CamConditionalAccess * cas, GObject * pmt,
|
||||
guint8 list_management, guint8 cmd_id)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint8 *buffer;
|
||||
guint buffer_size;
|
||||
guint offset;
|
||||
guint8 *ca_pmt;
|
||||
guint ca_pmt_size;
|
||||
GList *walk;
|
||||
|
||||
ca_pmt = cam_build_ca_pmt (pmt, list_management, cmd_id, &ca_pmt_size);
|
||||
cam_al_calc_buffer_size (CAM_AL_APPLICATION (cas)->al,
|
||||
ca_pmt_size, &buffer_size, &offset);
|
||||
|
||||
buffer = g_malloc0 (buffer_size);
|
||||
memcpy (buffer + offset, ca_pmt, ca_pmt_size);
|
||||
|
||||
for (walk = CAM_AL_APPLICATION (cas)->sessions; walk; walk = walk->next) {
|
||||
CamSLSession *session = CAM_SL_SESSION (walk->data);
|
||||
|
||||
ret = cam_al_application_write (CAM_AL_APPLICATION (cas), session,
|
||||
TAG_CONDITIONAL_ACCESS_PMT, buffer, buffer_size, ca_pmt_size);
|
||||
if (CAM_FAILED (ret)) {
|
||||
GST_ERROR ("error sending ca_pmt to slot %d, error: %d",
|
||||
session->connection->slot, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (ca_pmt);
|
||||
g_free (buffer);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_conditional_access_set_pmt (CamConditionalAccess * cas,
|
||||
GObject * pmt, CamConditionalAccessPmtFlag flag)
|
||||
{
|
||||
return send_ca_pmt (cas, pmt, flag, 0x01 /* ok_descrambling */ );
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_simple (CamConditionalAccess * cas, CamSLSession * session, guint tag)
|
||||
{
|
||||
guint8 *buffer;
|
||||
guint offset;
|
||||
guint buffer_size;
|
||||
CamReturn ret;
|
||||
|
||||
cam_al_calc_buffer_size (CAM_AL_APPLICATION (cas)->al, 0, &buffer_size,
|
||||
&offset);
|
||||
buffer = g_malloc (buffer_size);
|
||||
|
||||
ret = cam_al_application_write (CAM_AL_APPLICATION (cas), session,
|
||||
tag, buffer, buffer_size, 0);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_conditional_access_enquiry (CamConditionalAccess * cas,
|
||||
CamSLSession * session)
|
||||
{
|
||||
GST_DEBUG ("sending application cas enquiry");
|
||||
return send_simple (cas, session, TAG_CONDITIONAL_ACCESS_INFO_ENQUIRY);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
session_request_impl (CamALApplication * application,
|
||||
CamSLSession * session, CamSLResourceStatus * status)
|
||||
{
|
||||
*status = CAM_SL_RESOURCE_STATUS_OPEN;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
open_impl (CamALApplication * application, CamSLSession * session)
|
||||
{
|
||||
CamConditionalAccess *cas = CAM_CONDITIONAL_ACCESS (application);
|
||||
|
||||
GST_INFO ("opening conditional access session %d", session->session_nb);
|
||||
|
||||
return send_conditional_access_enquiry (cas, session);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
close_impl (CamALApplication * application, CamSLSession * session)
|
||||
{
|
||||
GST_INFO ("closing conditional access session %d", session->session_nb);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_conditional_access_info_reply (CamConditionalAccess * cas,
|
||||
CamSLSession * session, guint8 * buffer, guint length)
|
||||
{
|
||||
int i;
|
||||
guint16 cas_id;
|
||||
|
||||
GST_INFO ("conditional access info enquiry reply");
|
||||
|
||||
for (i = 0; i < length / 2; ++i) {
|
||||
cas_id = GST_READ_UINT16_BE (buffer);
|
||||
|
||||
GST_INFO ("slot %d, cas_id 0x%x", session->connection->slot, cas_id);
|
||||
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
cas->ready = TRUE;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
data_impl (CamALApplication * application, CamSLSession * session,
|
||||
guint tag, guint8 * buffer, guint length)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamConditionalAccess *cas = CAM_CONDITIONAL_ACCESS (application);
|
||||
|
||||
switch (tag) {
|
||||
case TAG_CONDITIONAL_ACCESS_INFO_REPLY:
|
||||
ret = handle_conditional_access_info_reply (cas, session, buffer, length);
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (CAM_RETURN_ERROR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
55
sys/dvb/camconditionalaccess.h
Normal file
55
sys/dvb/camconditionalaccess.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* camconditionalaccess.h - CAM (EN50221) Conditional Access resource
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAM_CONDITIONAL_ACCESS_H
|
||||
#define CAM_CONDITIONAL_ACCESS_H
|
||||
|
||||
#include "camapplication.h"
|
||||
|
||||
#define CAM_CONDITIONAL_ACCESS(obj) ((CamConditionalAccess *) obj)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAM_CONDITIONAL_ACCESS_PMT_FLAG_MORE = 0,
|
||||
CAM_CONDITIONAL_ACCESS_PMT_FLAG_FIRST,
|
||||
CAM_CONDITIONAL_ACCESS_PMT_FLAG_LAST,
|
||||
CAM_CONDITIONAL_ACCESS_PMT_FLAG_ONLY,
|
||||
CAM_CONDITIONAL_ACCESS_PMT_FLAG_ADD,
|
||||
CAM_CONDITIONAL_ACCESS_PMT_FLAG_UPDATE,
|
||||
} CamConditionalAccessPmtFlag;
|
||||
|
||||
typedef struct _CamConditionalAccess CamConditionalAccess;
|
||||
|
||||
struct _CamConditionalAccess
|
||||
{
|
||||
CamALApplication application;
|
||||
gboolean ready;
|
||||
};
|
||||
|
||||
CamConditionalAccess *cam_conditional_access_new ();
|
||||
void cam_conditional_access_destroy (CamConditionalAccess *cas);
|
||||
|
||||
CamReturn cam_conditional_access_set_pmt (CamConditionalAccess *cas,
|
||||
GObject *pmt, CamConditionalAccessPmtFlag flag);
|
||||
|
||||
#endif /* CAM_CONDITIONAL_ACCESS_H */
|
213
sys/dvb/camdevice.c
Normal file
213
sys/dvb/camdevice.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* camdevice.c - GStreamer hardware CAM support
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
|
||||
#include "camdevice.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
|
||||
CamDevice *
|
||||
cam_device_new ()
|
||||
{
|
||||
CamDevice *device = g_new0 (CamDevice, 1);
|
||||
|
||||
device->state = CAM_DEVICE_STATE_CLOSED;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_state (CamDevice * device)
|
||||
{
|
||||
if (device->filename) {
|
||||
g_free (device->filename);
|
||||
device->filename = NULL;
|
||||
}
|
||||
|
||||
if (device->fd) {
|
||||
close (device->fd);
|
||||
device->fd = -1;
|
||||
}
|
||||
|
||||
if (device->cas) {
|
||||
cam_conditional_access_destroy (device->cas);
|
||||
device->cas = NULL;
|
||||
}
|
||||
|
||||
if (device->mgr) {
|
||||
cam_resource_manager_destroy (device->mgr);
|
||||
device->mgr = NULL;
|
||||
}
|
||||
|
||||
if (device->info) {
|
||||
cam_application_info_destroy (device->info);
|
||||
device->info = NULL;
|
||||
}
|
||||
|
||||
if (device->al) {
|
||||
cam_al_destroy (device->al);
|
||||
device->al = NULL;
|
||||
}
|
||||
|
||||
if (device->sl) {
|
||||
cam_sl_destroy (device->sl);
|
||||
device->sl = NULL;
|
||||
}
|
||||
|
||||
if (device->tl) {
|
||||
cam_tl_destroy (device->tl);
|
||||
device->tl = NULL;
|
||||
}
|
||||
|
||||
device->state = CAM_DEVICE_STATE_CLOSED;
|
||||
}
|
||||
|
||||
void
|
||||
cam_device_free (CamDevice * device)
|
||||
{
|
||||
if (device->state != CAM_DEVICE_STATE_CLOSED)
|
||||
GST_WARNING ("device not in CLOSED state when free'd");
|
||||
|
||||
reset_state (device);
|
||||
g_free (device);
|
||||
}
|
||||
|
||||
gboolean
|
||||
cam_device_open (CamDevice * device, const char *filename)
|
||||
{
|
||||
ca_caps_t ca_caps;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (device != NULL, FALSE);
|
||||
g_return_val_if_fail (device->state == CAM_DEVICE_STATE_CLOSED, FALSE);
|
||||
g_return_val_if_fail (filename != NULL, FALSE);
|
||||
|
||||
GST_INFO ("opening ca device %s", filename);
|
||||
|
||||
ret = open (filename, O_RDWR);
|
||||
if (ret == -1) {
|
||||
GST_ERROR ("can't open ca device: %s", strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
device->fd = ret;
|
||||
|
||||
ret = ioctl (device->fd, CA_RESET);
|
||||
sleep (1);
|
||||
|
||||
/* get the capabilities of the CA */
|
||||
ret = ioctl (device->fd, CA_GET_CAP, &ca_caps);
|
||||
if (ret == -1) {
|
||||
GST_ERROR ("CA_GET_CAP ioctl failed: %s", strerror (errno));
|
||||
reset_state (device);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
device->tl = cam_tl_new (device->fd);
|
||||
device->sl = cam_sl_new (device->tl);
|
||||
device->al = cam_al_new (device->sl);
|
||||
|
||||
device->mgr = cam_resource_manager_new ();
|
||||
cam_al_install (device->al, CAM_AL_APPLICATION (device->mgr));
|
||||
|
||||
device->info = cam_application_info_new ();
|
||||
cam_al_install (device->al, CAM_AL_APPLICATION (device->info));
|
||||
|
||||
device->cas = cam_conditional_access_new ();
|
||||
cam_al_install (device->al, CAM_AL_APPLICATION (device->cas));
|
||||
|
||||
/* open a connection to each slot */
|
||||
for (i = 0; i < ca_caps.slot_num; ++i) {
|
||||
CamTLConnection *connection;
|
||||
|
||||
ret = cam_tl_create_connection (device->tl, i, &connection);
|
||||
if (CAM_FAILED (ret)) {
|
||||
/* just ignore the slot, error out later only if no connection has been
|
||||
* established */
|
||||
GST_WARNING ("connection to slot %d failed, error: %d", i, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_hash_table_size (device->tl->connections) == 0) {
|
||||
GST_ERROR ("couldn't connect to any slot");
|
||||
|
||||
reset_state (device);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
device->state = CAM_DEVICE_STATE_OPEN;
|
||||
device->filename = g_strdup (filename);
|
||||
|
||||
/* poll each connection to initiate the protocol */
|
||||
cam_tl_read_all (device->tl, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
cam_device_close (CamDevice * device)
|
||||
{
|
||||
g_return_if_fail (device != NULL);
|
||||
g_return_if_fail (device->state == CAM_DEVICE_STATE_OPEN);
|
||||
|
||||
GST_INFO ("closing ca device %s", device->filename);
|
||||
reset_state (device);
|
||||
}
|
||||
|
||||
void
|
||||
cam_device_poll (CamDevice * device)
|
||||
{
|
||||
g_return_if_fail (device != NULL);
|
||||
g_return_if_fail (device->state == CAM_DEVICE_STATE_OPEN);
|
||||
|
||||
cam_tl_read_all (device->tl, TRUE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
cam_device_ready (CamDevice * device)
|
||||
{
|
||||
g_return_val_if_fail (device != NULL, FALSE);
|
||||
g_return_val_if_fail (device->state == CAM_DEVICE_STATE_OPEN, FALSE);
|
||||
|
||||
return device->cas->ready;
|
||||
}
|
||||
|
||||
void
|
||||
cam_device_set_pmt (CamDevice * device,
|
||||
GObject * pmt, CamConditionalAccessPmtFlag flag)
|
||||
{
|
||||
g_return_if_fail (device != NULL);
|
||||
g_return_if_fail (device->state == CAM_DEVICE_STATE_OPEN);
|
||||
g_return_if_fail (pmt != NULL);
|
||||
|
||||
cam_conditional_access_set_pmt (device->cas, pmt, flag);
|
||||
cam_tl_read_all (device->tl, FALSE);
|
||||
}
|
69
sys/dvb/camdevice.h
Normal file
69
sys/dvb/camdevice.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* camdevice.h - GStreamer hardware CAM interface
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_DEVICE_H
|
||||
#define CAM_DEVICE_H
|
||||
|
||||
#include "camtransport.h"
|
||||
#include "camsession.h"
|
||||
#include "camapplication.h"
|
||||
#include "camresourcemanager.h"
|
||||
#include "camapplicationinfo.h"
|
||||
#include "camconditionalaccess.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAM_DEVICE_STATE_CLOSED,
|
||||
CAM_DEVICE_STATE_OPEN,
|
||||
} CamDeviceState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* private */
|
||||
CamDeviceState state;
|
||||
char *filename;
|
||||
int fd;
|
||||
|
||||
/* EN50221 layers */
|
||||
CamTL *tl;
|
||||
CamSL *sl;
|
||||
CamAL *al;
|
||||
|
||||
/* apps provided by us */
|
||||
CamResourceManager *mgr;
|
||||
CamApplicationInfo *info;
|
||||
CamConditionalAccess *cas;
|
||||
} CamDevice;
|
||||
|
||||
CamDevice *cam_device_new ();
|
||||
void cam_device_free (CamDevice *device);
|
||||
|
||||
gboolean cam_device_open (CamDevice *device, const char *filename);
|
||||
void cam_device_close (CamDevice *device);
|
||||
|
||||
gboolean cam_device_ready (CamDevice *device);
|
||||
void cam_device_poll (CamDevice *device);
|
||||
void cam_device_set_pmt (CamDevice *device,
|
||||
GObject *pmt, CamConditionalAccessPmtFlag flag);
|
||||
|
||||
#endif /* CAM_DEVICE_H */
|
192
sys/dvb/camresourcemanager.c
Normal file
192
sys/dvb/camresourcemanager.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* camresourcemanager.c - GStreamer CAM (EN50221) Resource Manager
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "camresourcemanager.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
#define TAG_PROFILE_ENQUIRY 0x9F8010
|
||||
#define TAG_PROFILE_REPLY 0x9F8011
|
||||
#define TAG_PROFILE_CHANGE 0x9F8012
|
||||
|
||||
static CamReturn session_request_impl (CamALApplication * application,
|
||||
CamSLSession * session, CamSLResourceStatus * status);
|
||||
static CamReturn open_impl (CamALApplication * application,
|
||||
CamSLSession * session);
|
||||
static CamReturn close_impl (CamALApplication * application,
|
||||
CamSLSession * session);
|
||||
static CamReturn data_impl (CamALApplication * application,
|
||||
CamSLSession * session, guint tag, guint8 * buffer, guint length);
|
||||
|
||||
CamResourceManager *
|
||||
cam_resource_manager_new ()
|
||||
{
|
||||
CamALApplication *application;
|
||||
CamResourceManager *mgr;
|
||||
|
||||
mgr = g_new0 (CamResourceManager, 1);
|
||||
application = CAM_AL_APPLICATION (mgr);
|
||||
_cam_al_application_init (application);
|
||||
application->resource_id = CAM_AL_RESOURCE_MANAGER_ID;
|
||||
application->session_request = session_request_impl;
|
||||
application->open = open_impl;
|
||||
application->close = close_impl;
|
||||
application->data = data_impl;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
void
|
||||
cam_resource_manager_destroy (CamResourceManager * mgr)
|
||||
{
|
||||
_cam_al_application_destroy (CAM_AL_APPLICATION (mgr));
|
||||
g_free (mgr);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
session_request_impl (CamALApplication * application,
|
||||
CamSLSession * session, CamSLResourceStatus * status)
|
||||
{
|
||||
*status = CAM_SL_RESOURCE_STATUS_OPEN;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_simple (CamResourceManager * mgr, CamSLSession * session, guint tag)
|
||||
{
|
||||
guint8 *buffer;
|
||||
guint offset;
|
||||
guint buffer_size;
|
||||
CamReturn ret;
|
||||
|
||||
cam_al_calc_buffer_size (CAM_AL_APPLICATION (mgr)->al, 0, &buffer_size,
|
||||
&offset);
|
||||
buffer = g_malloc (buffer_size);
|
||||
|
||||
ret = cam_al_application_write (CAM_AL_APPLICATION (mgr), session,
|
||||
tag, buffer, buffer_size, 0);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_profile_enquiry (CamResourceManager * mgr, CamSLSession * session)
|
||||
{
|
||||
GST_DEBUG ("sending profile enquiry");
|
||||
return send_simple (mgr, session, TAG_PROFILE_ENQUIRY);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_profile_change (CamResourceManager * mgr, CamSLSession * session)
|
||||
{
|
||||
GST_DEBUG ("sending profile change");
|
||||
return send_simple (mgr, session, TAG_PROFILE_CHANGE);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_profile_reply (CamResourceManager * mgr, CamSLSession * session)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint8 *buffer;
|
||||
guint8 *apdu_body;
|
||||
guint buffer_size;
|
||||
guint offset;
|
||||
GList *resource_ids;
|
||||
guint resource_ids_size;
|
||||
GList *walk;
|
||||
|
||||
resource_ids = cam_al_get_resource_ids (CAM_AL_APPLICATION (mgr)->al);
|
||||
resource_ids_size = g_list_length (resource_ids) * 4;
|
||||
|
||||
cam_al_calc_buffer_size (CAM_AL_APPLICATION (mgr)->al, resource_ids_size,
|
||||
&buffer_size, &offset);
|
||||
|
||||
buffer = g_malloc (buffer_size);
|
||||
apdu_body = buffer + offset;
|
||||
|
||||
for (walk = resource_ids; walk != NULL; walk = walk->next) {
|
||||
GST_WRITE_UINT32_BE (apdu_body, walk->data);
|
||||
|
||||
apdu_body += 4;
|
||||
}
|
||||
|
||||
g_list_free (resource_ids);
|
||||
|
||||
GST_DEBUG ("sending profile reply");
|
||||
ret = cam_al_application_write (CAM_AL_APPLICATION (mgr), session,
|
||||
TAG_PROFILE_REPLY, buffer, buffer_size, resource_ids_size);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
open_impl (CamALApplication * application, CamSLSession * session)
|
||||
{
|
||||
CamResourceManager *mgr = CAM_RESOURCE_MANAGER (application);
|
||||
|
||||
return send_profile_enquiry (mgr, session);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
close_impl (CamALApplication * application, CamSLSession * session)
|
||||
{
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_profile_reply (CamResourceManager * mgr, CamSLSession * session,
|
||||
guint8 * buffer, guint length)
|
||||
{
|
||||
/* the APDU contains length / 4 resource_ids */
|
||||
/* FIXME: implement this once CamApplicationProxy is implemented */
|
||||
GST_DEBUG ("got profile reply");
|
||||
return send_profile_change (mgr, session);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
data_impl (CamALApplication * application, CamSLSession * session,
|
||||
guint tag, guint8 * buffer, guint length)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamResourceManager *mgr = CAM_RESOURCE_MANAGER (application);
|
||||
|
||||
switch (tag) {
|
||||
case TAG_PROFILE_ENQUIRY:
|
||||
ret = send_profile_reply (mgr, session);
|
||||
break;
|
||||
case TAG_PROFILE_REPLY:
|
||||
ret = handle_profile_reply (mgr, session, buffer, length);
|
||||
break;
|
||||
case TAG_PROFILE_CHANGE:
|
||||
ret = send_profile_enquiry (mgr, session);
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (CAM_RETURN_APPLICATION_ERROR);
|
||||
}
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
41
sys/dvb/camresourcemanager.h
Normal file
41
sys/dvb/camresourcemanager.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* camresourcemanager.h - GStreamer CAM (EN50221) Resource Manager
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_RESOURCE_MANAGER_H
|
||||
#define CAM_RESOURCE_MANAGER_H
|
||||
|
||||
#include "camapplication.h"
|
||||
|
||||
#define CAM_RESOURCE_MANAGER(obj) ((CamResourceManager *) obj)
|
||||
|
||||
typedef struct _CamResourceManager CamResourceManager;
|
||||
|
||||
struct _CamResourceManager
|
||||
{
|
||||
CamALApplication application;
|
||||
};
|
||||
|
||||
CamResourceManager *cam_resource_manager_new ();
|
||||
void cam_resource_manager_destroy (CamResourceManager *manager);
|
||||
|
||||
#endif /* CAM_RESOURCE_MANAGER_H */
|
595
sys/dvb/camsession.c
Normal file
595
sys/dvb/camsession.c
Normal file
|
@ -0,0 +1,595 @@
|
|||
/*
|
||||
* camsession.c - GStreamer CAM (EN50221) Session Layer
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "camsession.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
#define I_TAG 0
|
||||
#define I_LENGTH_FB 1
|
||||
|
||||
#define TAG_SESSION_NUMBER 0x90
|
||||
#define TAG_OPEN_SESSION_REQUEST 0x91
|
||||
#define TAG_OPEN_SESSION_RESPONSE 0x92
|
||||
#define TAG_CREATE_SESSION 0x93
|
||||
#define TAG_CREATE_SESSION_RESPONSE 0x94
|
||||
#define TAG_CLOSE_SESSION_REQUEST 0x95
|
||||
#define TAG_CLOSE_SESSION_RESPONSE 0x96
|
||||
|
||||
static CamReturn connection_data_cb (CamTL * tl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint spdu_length);
|
||||
|
||||
CamSLSession *
|
||||
cam_sl_session_new (CamSL * sl, CamTLConnection * connection,
|
||||
guint16 session_nb, guint resource_id)
|
||||
{
|
||||
CamSLSession *session = g_new0 (CamSLSession, 1);
|
||||
|
||||
session->state = CAM_SL_SESSION_STATE_IDLE;
|
||||
session->sl = sl;
|
||||
session->connection = connection;
|
||||
session->session_nb = session_nb;
|
||||
session->resource_id = resource_id;
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void
|
||||
cam_sl_session_destroy (CamSLSession * session)
|
||||
{
|
||||
g_free (session);
|
||||
}
|
||||
|
||||
CamSL *
|
||||
cam_sl_new (CamTL * tl)
|
||||
{
|
||||
CamSL *sl = g_new0 (CamSL, 1);
|
||||
|
||||
sl->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, (GDestroyNotify) cam_sl_session_destroy);
|
||||
|
||||
tl->user_data = sl;
|
||||
tl->connection_data = connection_data_cb;
|
||||
|
||||
return sl;
|
||||
}
|
||||
|
||||
void
|
||||
cam_sl_destroy (CamSL * sl)
|
||||
{
|
||||
g_hash_table_destroy (sl->sessions);
|
||||
|
||||
g_free (sl);
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_sl_create_session (CamSL * sl,
|
||||
CamTLConnection * connection, guint resource_id,
|
||||
CamSLSession ** out_session)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamSLSession *session = NULL;
|
||||
guint size;
|
||||
guint offset;
|
||||
guint8 *tpdu = NULL;
|
||||
guint8 *spdu;
|
||||
guint16 session_nb;
|
||||
|
||||
/* FIXME: implement session number allocations properly */
|
||||
if (sl->session_ids == G_MAXUINT16)
|
||||
return CAM_RETURN_SESSION_TOO_MANY_SESSIONS;
|
||||
|
||||
session_nb = ++sl->session_ids;
|
||||
session = cam_sl_session_new (sl, connection, session_nb, resource_id);
|
||||
|
||||
/* SPDU layout (8 bytes):
|
||||
* TAG_CREATE_SESSION 1 byte
|
||||
* length_field () 1 byte
|
||||
* resource_id 4 bytes
|
||||
* session_nb 2 bytes
|
||||
*/
|
||||
|
||||
/* get TPDU size */
|
||||
cam_tl_calc_buffer_size (sl->tl, 8, &size, &offset);
|
||||
|
||||
tpdu = (guint8 *) g_malloc (size);
|
||||
spdu = tpdu + offset;
|
||||
|
||||
/* SPDU header */
|
||||
/* tag */
|
||||
spdu[0] = TAG_CREATE_SESSION;
|
||||
/* fixed length_field */
|
||||
spdu[1] = 6;
|
||||
|
||||
/* SPDU body */
|
||||
/* resource id */
|
||||
GST_WRITE_UINT32_BE (&spdu[2], resource_id);
|
||||
/* session_nb */
|
||||
GST_WRITE_UINT16_BE (&spdu[6], session_nb);
|
||||
|
||||
/* write the TPDU */
|
||||
ret = cam_tl_connection_write (session->connection, tpdu, size, 8);
|
||||
if (CAM_FAILED (ret))
|
||||
goto error;
|
||||
|
||||
*out_session = session;
|
||||
|
||||
g_free (tpdu);
|
||||
return CAM_RETURN_OK;
|
||||
|
||||
error:
|
||||
if (session)
|
||||
cam_sl_session_destroy (session);
|
||||
|
||||
g_free (tpdu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* send a TAG_CLOSE_SESSION SPDU */
|
||||
CamReturn
|
||||
cam_sl_session_close (CamSLSession * session)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint size;
|
||||
guint offset;
|
||||
guint8 *tpdu = NULL;
|
||||
guint8 *spdu;
|
||||
CamSL *sl = session->sl;
|
||||
|
||||
/* SPDU layout (4 bytes):
|
||||
* TAG_CLOSE_SESSION 1 byte
|
||||
* length_field () 1 byte
|
||||
* session_nb 2 bytes
|
||||
*/
|
||||
|
||||
/* get the size of the TPDU */
|
||||
cam_tl_calc_buffer_size (sl->tl, 4, &size, &offset);
|
||||
|
||||
tpdu = (guint8 *) g_malloc (size);
|
||||
/* the spdu header starts after the TPDU headers */
|
||||
spdu = tpdu + offset;
|
||||
|
||||
/* SPDU header */
|
||||
/* tag */
|
||||
spdu[0] = TAG_CLOSE_SESSION_REQUEST;
|
||||
/* fixed length_field */
|
||||
spdu[1] = 2;
|
||||
/* SPDU body */
|
||||
/* session_nb */
|
||||
GST_WRITE_UINT16_BE (&spdu[2], session->session_nb);
|
||||
|
||||
/* write the TPDU */
|
||||
ret = cam_tl_connection_write (session->connection, tpdu, size, 4);
|
||||
if (CAM_FAILED (ret))
|
||||
goto error;
|
||||
|
||||
session->state = CAM_SL_SESSION_STATE_CLOSING;
|
||||
|
||||
g_free (tpdu);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
|
||||
error:
|
||||
g_free (tpdu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
cam_sl_calc_buffer_size (CamSL * sl, guint body_length,
|
||||
guint * buffer_size, guint * offset)
|
||||
{
|
||||
/* an APDU is sent in a SESSION_NUMBER SPDU, which has a fixed header size (4
|
||||
* bytes) */
|
||||
cam_tl_calc_buffer_size (sl->tl, 4 + body_length, buffer_size, offset);
|
||||
*offset += 4;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_sl_session_write (CamSLSession * session,
|
||||
guint8 * buffer, guint buffer_size, guint body_length)
|
||||
{
|
||||
guint8 *spdu;
|
||||
|
||||
/* SPDU layout (4 + body_length bytes):
|
||||
* TAG_SESSION_NUMBER (1 byte)
|
||||
* length_field (1 byte)
|
||||
* session number (2 bytes)
|
||||
* one or more APDUs (body_length bytes)
|
||||
*/
|
||||
|
||||
spdu = (buffer + buffer_size) - body_length - 4;
|
||||
spdu[0] = TAG_SESSION_NUMBER;
|
||||
spdu[1] = 2;
|
||||
GST_WRITE_UINT16_BE (&spdu[2], session->session_nb);
|
||||
|
||||
/* add our header to the body length */
|
||||
return cam_tl_connection_write (session->connection,
|
||||
buffer, buffer_size, 4 + body_length);
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_open_session_response (CamSL * sl, CamSLSession * session, guint8 status)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint8 *tpdu;
|
||||
guint size;
|
||||
guint offset;
|
||||
guint8 *spdu;
|
||||
|
||||
/* SPDU layout (9 bytes):
|
||||
* TAG_OPEN_SESSION_RESPONSE 1 byte
|
||||
* length_field () 1 byte
|
||||
* session_status 1 byte
|
||||
* resource_id 4 bytes
|
||||
* session_nb 2 bytes
|
||||
*/
|
||||
|
||||
cam_tl_calc_buffer_size (session->sl->tl, 9, &size, &offset);
|
||||
|
||||
tpdu = g_malloc0 (size);
|
||||
spdu = tpdu + offset;
|
||||
|
||||
spdu[0] = TAG_OPEN_SESSION_RESPONSE;
|
||||
/* fixed length_field () */
|
||||
spdu[1] = 7;
|
||||
spdu[2] = status;
|
||||
GST_WRITE_UINT32_BE (&spdu[3], session->resource_id);
|
||||
GST_WRITE_UINT16_BE (&spdu[7], session->session_nb);
|
||||
|
||||
ret = cam_tl_connection_write (session->connection, tpdu, size, 9);
|
||||
g_free (tpdu);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
send_close_session_response (CamSL * sl, CamSLSession * session, guint8 status)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint8 *tpdu;
|
||||
guint size;
|
||||
guint offset;
|
||||
guint8 *spdu;
|
||||
|
||||
/* SPDU layout (5 bytes):
|
||||
* TAG_CLOSE_SESSION_RESPONSE 1 byte
|
||||
* length_field () 1 byte
|
||||
* session_status 1 byte
|
||||
* session_nb 2 bytes
|
||||
*/
|
||||
|
||||
cam_tl_calc_buffer_size (session->sl->tl, 5, &size, &offset);
|
||||
|
||||
tpdu = g_malloc0 (size);
|
||||
spdu = tpdu + offset;
|
||||
|
||||
spdu[0] = TAG_OPEN_SESSION_RESPONSE;
|
||||
/* fixed length_field() */
|
||||
spdu[1] = 3;
|
||||
spdu[2] = status;
|
||||
GST_WRITE_UINT16_BE (&spdu[3], session->session_nb);
|
||||
|
||||
ret = cam_tl_connection_write (session->connection, tpdu, size, 5);
|
||||
g_free (tpdu);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_open_session_request (CamSL * sl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint spdu_length)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint resource_id;
|
||||
guint status;
|
||||
guint16 session_nb;
|
||||
CamSLSession *session;
|
||||
|
||||
/* SPDU layout (6 bytes):
|
||||
* TAG_OPEN_SESSION_REQUEST (1 byte)
|
||||
* length_field() (1 byte)
|
||||
* resource id (4 bytes)
|
||||
*/
|
||||
if (spdu_length != 6) {
|
||||
GST_ERROR ("expected OPEN_SESSION_REQUEST to be 6 bytes, got %d",
|
||||
spdu_length);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
/* skip tag and length_field () */
|
||||
resource_id = GST_READ_UINT32_BE (&spdu[2]);
|
||||
|
||||
/* create a new session */
|
||||
if (sl->session_ids == G_MAXUINT16) {
|
||||
GST_ERROR ("too many sessions opened");
|
||||
return CAM_RETURN_SESSION_TOO_MANY_SESSIONS;
|
||||
}
|
||||
|
||||
session_nb = ++sl->session_ids;
|
||||
session = cam_sl_session_new (sl, connection, session_nb, resource_id);
|
||||
|
||||
GST_INFO ("session request: %d %x", session_nb, session->resource_id);
|
||||
|
||||
if (sl->open_session_request) {
|
||||
/* forward the request to the upper layer */
|
||||
ret = sl->open_session_request (sl, session, &status);
|
||||
if (CAM_FAILED (ret))
|
||||
goto error;
|
||||
} else {
|
||||
status = 0xF0;
|
||||
}
|
||||
|
||||
ret = send_open_session_response (sl, session, (guint8) status);
|
||||
if (CAM_FAILED (ret))
|
||||
goto error;
|
||||
|
||||
GST_INFO ("session request response: %d %x", session_nb, status);
|
||||
|
||||
if (status == CAM_SL_RESOURCE_STATUS_OPEN) {
|
||||
/* if the session has been accepted add it and signal */
|
||||
session->state = CAM_SL_SESSION_STATE_ACTIVE;
|
||||
g_hash_table_insert (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session_nb), session);
|
||||
|
||||
if (sl->session_opened) {
|
||||
/* notify the upper layer */
|
||||
ret = sl->session_opened (sl, session);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* session request wasn't accepted */
|
||||
cam_sl_session_destroy (session);
|
||||
}
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
|
||||
error:
|
||||
cam_sl_session_destroy (session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_create_session_response (CamSL * sl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint spdu_length)
|
||||
{
|
||||
guint8 status;
|
||||
guint resource_id;
|
||||
guint16 session_nb;
|
||||
CamSLSession *session;
|
||||
|
||||
/* SPDU layout (9 bytes):
|
||||
* TAG_CREATE_SESSION_RESPONSE (1 byte)
|
||||
* length_field() (1 byte)
|
||||
* status (1 byte)
|
||||
* resource id (4 bytes)
|
||||
* session number (2 bytes)
|
||||
*/
|
||||
if (spdu_length != 9) {
|
||||
GST_ERROR ("expected CREATE_SESSION_RESPONSE to be 9 bytes, got %d",
|
||||
spdu_length);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
/* skip tag and length */
|
||||
status = spdu[2];
|
||||
resource_id = GST_READ_UINT32_BE (&spdu[3]);
|
||||
session_nb = GST_READ_UINT16_BE (&spdu[7]);
|
||||
|
||||
session = g_hash_table_lookup (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session_nb));
|
||||
if (session == NULL) {
|
||||
GST_DEBUG ("got CREATE_SESSION_RESPONSE for unknown session: %d",
|
||||
session_nb);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
if (session->state == CAM_SL_SESSION_STATE_CLOSING) {
|
||||
GST_DEBUG ("ignoring CREATE_SESSION_RESPONSE for closing session: %d",
|
||||
session_nb);
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
session->state = CAM_SL_SESSION_STATE_ACTIVE;
|
||||
|
||||
GST_DEBUG ("session opened %d", session->session_nb);
|
||||
|
||||
if (sl->session_opened)
|
||||
/* notify the upper layer */
|
||||
return sl->session_opened (sl, session);
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_close_session_request (CamSL * sl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint spdu_length)
|
||||
{
|
||||
CamReturn ret;
|
||||
guint16 session_nb;
|
||||
CamSLSession *session;
|
||||
guint8 status = 0;
|
||||
|
||||
/* SPDU layout (4 bytes):
|
||||
* TAG_CLOSE_SESSION_REQUEST (1 byte)
|
||||
* length_field () (1 byte)
|
||||
* session number (2 bytes)
|
||||
*/
|
||||
if (spdu_length != 4) {
|
||||
GST_ERROR ("expected CLOSE_SESSION_REQUEST to be 4 bytes, got %d",
|
||||
spdu_length);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
/* skip tag and length_field() */
|
||||
session_nb = GST_READ_UINT16_BE (&spdu[2]);
|
||||
|
||||
GST_DEBUG ("close session request %d", session_nb);
|
||||
|
||||
session = g_hash_table_lookup (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session_nb));
|
||||
if (session == NULL) {
|
||||
GST_WARNING ("got CLOSE_SESSION_REQUEST for unknown session: %d",
|
||||
session_nb);
|
||||
|
||||
status = 0xF0;
|
||||
} else if (session->state == CAM_SL_SESSION_STATE_CLOSING) {
|
||||
GST_WARNING ("got CLOSE_SESSION_REQUEST for closing session: %d",
|
||||
session_nb);
|
||||
|
||||
status = 0xF0;
|
||||
}
|
||||
|
||||
GST_DEBUG ("close session response: %d %d", session->session_nb, status);
|
||||
|
||||
ret = send_close_session_response (sl, session, status);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
|
||||
if (session->state != CAM_SL_SESSION_STATE_CLOSING) {
|
||||
GST_DEBUG ("session closed %d", session->session_nb);
|
||||
|
||||
if (sl->session_closed)
|
||||
ret = sl->session_closed (sl, session);
|
||||
|
||||
g_hash_table_remove (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session->session_nb));
|
||||
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_close_session_response (CamSL * sl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint spdu_length)
|
||||
{
|
||||
guint16 session_nb;
|
||||
CamSLSession *session;
|
||||
CamReturn ret = CAM_RETURN_OK;
|
||||
|
||||
/* SPDU layout (5 bytes):
|
||||
* TAG_CLOSE_SESSION_RESPONSE (1 byte)
|
||||
* length_field () (1 byte)
|
||||
* status (1 byte)
|
||||
* session number (2 bytes)
|
||||
*/
|
||||
|
||||
if (spdu_length != 5) {
|
||||
GST_ERROR ("expected CLOSE_SESSION_RESPONSE to be 5 bytes, got %d",
|
||||
spdu_length);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
/* skip tag, length_field() and session_status */
|
||||
session_nb = GST_READ_UINT16_BE (&spdu[3]);
|
||||
|
||||
session = g_hash_table_lookup (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session_nb));
|
||||
if (session == NULL || session->state != CAM_SL_SESSION_STATE_ACTIVE) {
|
||||
GST_ERROR ("unexpected CLOSED_SESSION_RESPONSE");
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
GST_DEBUG ("session closed %d", session->session_nb);
|
||||
|
||||
if (sl->session_closed)
|
||||
ret = sl->session_closed (sl, session);
|
||||
|
||||
g_hash_table_remove (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session->session_nb));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
handle_session_data (CamSL * sl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint length)
|
||||
{
|
||||
guint16 session_nb;
|
||||
CamSLSession *session;
|
||||
|
||||
/* SPDU layout (>= 4 bytes):
|
||||
* TAG_SESSION_NUMBER (1 byte)
|
||||
* length_field() (1 byte)
|
||||
* session number (2 bytes)
|
||||
* one or more APDUs
|
||||
*/
|
||||
|
||||
if (length < 4) {
|
||||
GST_ERROR ("invalid SESSION_NUMBER SPDU length %d", length);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
session_nb = GST_READ_UINT16_BE (&spdu[2]);
|
||||
|
||||
session = g_hash_table_lookup (sl->sessions,
|
||||
GINT_TO_POINTER ((guint) session_nb));
|
||||
if (session == NULL) {
|
||||
GST_ERROR ("got SESSION_NUMBER on an unknown connection: %d", session_nb);
|
||||
return CAM_RETURN_SESSION_ERROR;
|
||||
}
|
||||
|
||||
if (sl->session_data)
|
||||
/* pass the APDUs to the upper layer, removing our 4-bytes header */
|
||||
return sl->session_data (sl, session, spdu + 4, length - 4);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static CamReturn
|
||||
connection_data_cb (CamTL * tl, CamTLConnection * connection,
|
||||
guint8 * spdu, guint spdu_length)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamSL *sl = CAM_SL (tl->user_data);
|
||||
|
||||
switch (spdu[I_TAG]) {
|
||||
case TAG_CREATE_SESSION_RESPONSE:
|
||||
ret = handle_create_session_response (sl, connection, spdu, spdu_length);
|
||||
break;
|
||||
case TAG_OPEN_SESSION_REQUEST:
|
||||
ret = handle_open_session_request (sl, connection, spdu, spdu_length);
|
||||
break;
|
||||
case TAG_CLOSE_SESSION_REQUEST:
|
||||
ret = handle_close_session_request (sl, connection, spdu, spdu_length);
|
||||
break;
|
||||
case TAG_CLOSE_SESSION_RESPONSE:
|
||||
ret = handle_close_session_response (sl, connection, spdu, spdu_length);
|
||||
break;
|
||||
case TAG_SESSION_NUMBER:
|
||||
ret = handle_session_data (sl, connection, spdu, spdu_length);
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (CAM_RETURN_SESSION_ERROR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
96
sys/dvb/camsession.h
Normal file
96
sys/dvb/camsession.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* camsession.h - GStreamer CAM (EN50221) Session Layer
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_SESSION_H
|
||||
#define CAM_SESSION_H
|
||||
|
||||
#include "cam.h"
|
||||
#include "camtransport.h"
|
||||
|
||||
#define CAM_SL(obj) ((CamSL *) obj)
|
||||
#define CAM_SL_SESSION(obj) ((CamSLSession *) obj)
|
||||
|
||||
typedef struct _CamSL CamSL;
|
||||
typedef struct _CamSLSession CamSLSession;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAM_SL_SESSION_STATE_IDLE,
|
||||
CAM_SL_SESSION_STATE_OPENING,
|
||||
CAM_SL_SESSION_STATE_ACTIVE,
|
||||
CAM_SL_SESSION_STATE_CLOSING
|
||||
} CamSLSessionState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAM_SL_RESOURCE_STATUS_OPEN = 0x00,
|
||||
CAM_SL_RESOURCE_STATUS_NOT_FOUND = 0xF0,
|
||||
CAM_SL_RESOURCE_STATUS_UNAVAILABLE = 0xF1,
|
||||
CAM_SL_RESOURCE_STATUS_INVALID_VERSION = 0xF2,
|
||||
CAM_SL_RESOURCE_STATUS_BUSY = 0xF3
|
||||
} CamSLResourceStatus;
|
||||
|
||||
struct _CamSL
|
||||
{
|
||||
CamTL *tl;
|
||||
|
||||
GHashTable *sessions;
|
||||
guint session_ids;
|
||||
|
||||
/* callbacks */
|
||||
CamReturn (*open_session_request) (CamSL *sl, CamSLSession *session,
|
||||
CamSLResourceStatus *status);
|
||||
CamReturn (*session_opened) (CamSL *sl, CamSLSession *session);
|
||||
CamReturn (*session_closed) (CamSL *sl, CamSLSession *session);
|
||||
CamReturn (*session_data) (CamSL *sl, CamSLSession *session,
|
||||
guint8 *data, guint length);
|
||||
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
struct _CamSLSession
|
||||
{
|
||||
CamSL *sl;
|
||||
CamTLConnection *connection;
|
||||
|
||||
guint resource_id;
|
||||
guint16 session_nb;
|
||||
|
||||
CamSLSessionState state;
|
||||
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
CamSL *cam_sl_new (CamTL *transport);
|
||||
void cam_sl_destroy (CamSL *sl);
|
||||
|
||||
CamReturn cam_sl_create_session (CamSL *sl, CamTLConnection *connection,
|
||||
guint resource_id, CamSLSession **session);
|
||||
CamReturn cam_sl_session_close (CamSLSession *session);
|
||||
|
||||
void cam_sl_calc_buffer_size (CamSL *sl,
|
||||
guint body_length, guint *buffer_size, guint *offset);
|
||||
CamReturn cam_sl_session_write (CamSLSession *session,
|
||||
guint8 *buffe, guint buffer_size, guint body_length);
|
||||
|
||||
#endif /* CAM_SESSION_H */
|
162
sys/dvb/camswclient.c
Normal file
162
sys/dvb/camswclient.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* camswclient.c - GStreamer softcam client
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "camswclient.h"
|
||||
#include "cam.h"
|
||||
#include "camutils.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
#define UNIX_PATH_MAX 108
|
||||
|
||||
CamSwClient *
|
||||
cam_sw_client_new ()
|
||||
{
|
||||
CamSwClient *client = g_new0 (CamSwClient, 1);
|
||||
|
||||
client->state = CAM_SW_CLIENT_STATE_CLOSED;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_state (CamSwClient * client)
|
||||
{
|
||||
if (client->sock)
|
||||
close (client->sock);
|
||||
|
||||
if (client->sock_path)
|
||||
g_free (client->sock_path);
|
||||
}
|
||||
|
||||
void
|
||||
cam_sw_client_free (CamSwClient * client)
|
||||
{
|
||||
g_return_if_fail (client != NULL);
|
||||
|
||||
if (client->state != CAM_SW_CLIENT_STATE_CLOSED)
|
||||
GST_WARNING ("client not in CLOSED state when free'd");
|
||||
|
||||
reset_state (client);
|
||||
g_free (client);
|
||||
}
|
||||
|
||||
gboolean
|
||||
cam_sw_client_open (CamSwClient * client, const char *sock_path)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int ret;
|
||||
|
||||
g_return_val_if_fail (client != NULL, FALSE);
|
||||
g_return_val_if_fail (client->state == CAM_SW_CLIENT_STATE_CLOSED, FALSE);
|
||||
g_return_val_if_fail (sock_path != NULL, FALSE);
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy (addr.sun_path, sock_path, UNIX_PATH_MAX);
|
||||
|
||||
GST_INFO ("connecting to softcam socket: %s", sock_path);
|
||||
client->sock = socket (PF_UNIX, SOCK_STREAM, 0);
|
||||
ret =
|
||||
connect (client->sock, (struct sockaddr *) &addr,
|
||||
sizeof (struct sockaddr_un));
|
||||
if (ret != 0) {
|
||||
GST_ERROR ("error opening softcam socket %s, error: %s",
|
||||
sock_path, strerror (errno));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
client->sock_path = g_strdup (sock_path);
|
||||
client->state = CAM_SW_CLIENT_STATE_OPEN;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
cam_sw_client_close (CamSwClient * client)
|
||||
{
|
||||
g_return_if_fail (client != NULL);
|
||||
g_return_if_fail (client->state == CAM_SW_CLIENT_STATE_OPEN);
|
||||
|
||||
reset_state (client);
|
||||
client->state = CAM_SW_CLIENT_STATE_CLOSED;
|
||||
}
|
||||
|
||||
static void
|
||||
send_ca_pmt (CamSwClient * client, GObject * pmt,
|
||||
guint8 list_management, guint8 cmd_id)
|
||||
{
|
||||
guint8 *buffer;
|
||||
guint buffer_size;
|
||||
guint8 *ca_pmt;
|
||||
guint ca_pmt_size;
|
||||
guint length_field_len;
|
||||
guint header_len;
|
||||
|
||||
ca_pmt = cam_build_ca_pmt (pmt, list_management, cmd_id, &ca_pmt_size);
|
||||
|
||||
length_field_len = cam_calc_length_field_size (ca_pmt_size);
|
||||
header_len = 3 + length_field_len;
|
||||
buffer_size = header_len + ca_pmt_size;
|
||||
|
||||
buffer = g_malloc0 (buffer_size);
|
||||
memcpy (buffer + header_len, ca_pmt, ca_pmt_size);
|
||||
|
||||
/* ca_pmt resource_id */
|
||||
buffer[0] = 0x9F;
|
||||
buffer[1] = 0x80;
|
||||
buffer[2] = 0x32;
|
||||
|
||||
cam_write_length_field (&buffer[3], ca_pmt_size);
|
||||
|
||||
write (client->sock, buffer, buffer_size);
|
||||
|
||||
g_free (ca_pmt);
|
||||
g_free (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
cam_sw_client_set_pmt (CamSwClient * client, GObject * pmt)
|
||||
{
|
||||
g_return_if_fail (client != NULL);
|
||||
g_return_if_fail (pmt != NULL);
|
||||
|
||||
return send_ca_pmt (client, pmt, 0x03 /* only */ ,
|
||||
0x01 /* ok_descrambling */ );
|
||||
}
|
||||
|
||||
void
|
||||
cam_sw_client_update_pmt (CamSwClient * client, GObject * pmt)
|
||||
{
|
||||
g_return_if_fail (client != NULL);
|
||||
g_return_if_fail (pmt != NULL);
|
||||
|
||||
return send_ca_pmt (client, pmt, 0x05 /* update */ ,
|
||||
0x01 /* ok_descrambling */ );
|
||||
}
|
53
sys/dvb/camswclient.h
Normal file
53
sys/dvb/camswclient.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* camswclient.h - GStreamer softcam client
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_SW_CLIENT_H
|
||||
#define CAM_SW_CLIENT_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAM_SW_CLIENT_STATE_CLOSED,
|
||||
CAM_SW_CLIENT_STATE_OPEN,
|
||||
} CamSwClientState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* private */
|
||||
CamSwClientState state;
|
||||
char *sock_path;
|
||||
int sock;
|
||||
|
||||
} CamSwClient;
|
||||
|
||||
CamSwClient *cam_sw_client_new ();
|
||||
void cam_sw_client_free (CamSwClient *sw_client);
|
||||
|
||||
gboolean cam_sw_client_open (CamSwClient *sw_client, const char *sock_path);
|
||||
void cam_sw_client_close (CamSwClient *sw_client);
|
||||
|
||||
void cam_sw_client_set_pmt (CamSwClient *sw_client, GObject *pmt);
|
||||
void cam_sw_client_update_pmt (CamSwClient *sw_client, GObject *pmt);
|
||||
|
||||
#endif /* CAM_SW_CLIENT_H */
|
505
sys/dvb/camtransport.c
Normal file
505
sys/dvb/camtransport.c
Normal file
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* camtransport.c - GStreamer CAM (EN50221) transport layer
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "camtransport.h"
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
#define READ_TIMEOUT_SEC 2
|
||||
#define READ_TIMEOUT_USEC 0
|
||||
|
||||
#define POLL_INTERVAL 0.300
|
||||
|
||||
#define TAG_SB 0x80
|
||||
#define TAG_RCV 0x81
|
||||
#define TAG_CREATE_T_C 0x82
|
||||
#define TAG_C_T_C_REPLY 0x83
|
||||
#define TAG_DELETE_T_C 0x84
|
||||
#define TAG_D_T_C_REPLY 0x85
|
||||
#define TAG_REQUEST_T_C 0x86
|
||||
#define TAG_NEW_T_C 0x87
|
||||
#define TAG_T_C_ERROR 0x88
|
||||
#define TAG_DATA_MORE 0xA1
|
||||
#define TAG_DATA_LAST 0xA0
|
||||
|
||||
/* utility struct used to store the state of the connections in cam_tl_read_next
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GList *active;
|
||||
GList *idle;
|
||||
} CamTLConnectionsStatus;
|
||||
|
||||
void cam_gst_util_dump_mem (const guchar * mem, guint size);
|
||||
|
||||
CamTLConnection *
|
||||
cam_tl_connection_new (CamTL * tl, guint8 id)
|
||||
{
|
||||
CamTLConnection *connection;
|
||||
|
||||
connection = g_new0 (CamTLConnection, 1);
|
||||
connection->tl = tl;
|
||||
connection->id = id;
|
||||
connection->state = CAM_TL_CONNECTION_STATE_CLOSED;
|
||||
connection->has_data = FALSE;
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
static void
|
||||
cam_tl_connection_destroy (CamTLConnection * connection)
|
||||
{
|
||||
if (connection->last_poll)
|
||||
g_timer_destroy (connection->last_poll);
|
||||
|
||||
g_free (connection);
|
||||
}
|
||||
|
||||
CamTL *
|
||||
cam_tl_new (int fd)
|
||||
{
|
||||
CamTL *tl;
|
||||
|
||||
tl = g_new0 (CamTL, 1);
|
||||
tl->fd = fd;
|
||||
tl->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, (GDestroyNotify) cam_tl_connection_destroy);
|
||||
|
||||
return tl;
|
||||
}
|
||||
|
||||
void
|
||||
cam_tl_destroy (CamTL * tl)
|
||||
{
|
||||
g_hash_table_destroy (tl->connections);
|
||||
|
||||
g_free (tl);
|
||||
}
|
||||
|
||||
/* read data from the module without blocking indefinitely */
|
||||
static CamReturn
|
||||
cam_tl_read_timeout (CamTL * tl, struct timeval *timeout)
|
||||
{
|
||||
fd_set read_fd;
|
||||
int sret;
|
||||
|
||||
FD_ZERO (&read_fd);
|
||||
FD_SET (tl->fd, &read_fd);
|
||||
|
||||
sret = select (tl->fd + 1, &read_fd, NULL, NULL, timeout);
|
||||
if (sret == 0) {
|
||||
GST_DEBUG ("read timeout");
|
||||
return CAM_RETURN_TRANSPORT_TIMEOUT;
|
||||
}
|
||||
|
||||
tl->buffer_size = read (tl->fd, &tl->buffer, HOST_BUFFER_SIZE);
|
||||
if (tl->buffer_size == -1) {
|
||||
GST_ERROR ("error reading tpdu: %s", g_strerror (errno));
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
/* read data from the module using the default timeout */
|
||||
static CamReturn
|
||||
cam_tl_read (CamTL * tl)
|
||||
{
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = READ_TIMEOUT_SEC;
|
||||
timeout.tv_usec = READ_TIMEOUT_USEC;
|
||||
|
||||
return cam_tl_read_timeout (tl, &timeout);
|
||||
}
|
||||
|
||||
/* get the number of bytes to allocate for a TPDU with a body of body_length
|
||||
* bytes. Also get the offset from the beginning of the buffer that marks the
|
||||
* position of the first byte of the TPDU body */
|
||||
void
|
||||
cam_tl_calc_buffer_size (CamTL * tl, guint body_length,
|
||||
guint * buffer_size, guint * offset)
|
||||
{
|
||||
guint length_field_len;
|
||||
|
||||
/* the size of a TPDU is:
|
||||
* 1 byte slot number
|
||||
* 1 byte connection id
|
||||
* length_field_len bytes length field
|
||||
* 1 byte connection id
|
||||
* body_length bytes body
|
||||
*/
|
||||
|
||||
/* get the length of the lenght_field block */
|
||||
length_field_len = cam_calc_length_field_size (body_length);
|
||||
|
||||
*offset = 3 + length_field_len + 1;
|
||||
*buffer_size = *offset + body_length;
|
||||
}
|
||||
|
||||
/* write the header of a TPDU
|
||||
* NOTE: this function assumes that the buffer is large enough to contain the
|
||||
* complete TPDU (see cam_tl_calc_buffer_size ()) and that enough space has been
|
||||
* left from the beginning of the buffer to write the TPDU header.
|
||||
*/
|
||||
static CamReturn
|
||||
cam_tl_connection_write_tpdu (CamTLConnection * connection,
|
||||
guint8 tag, guint8 * buffer, guint buffer_size, guint body_length)
|
||||
{
|
||||
int sret;
|
||||
CamTL *tl = connection->tl;
|
||||
guint8 length_field_len;
|
||||
|
||||
/* slot number */
|
||||
buffer[0] = connection->slot;
|
||||
/* connection number */
|
||||
buffer[1] = connection->id;
|
||||
/* tag */
|
||||
buffer[2] = tag;
|
||||
/* length can take 1 to 4 bytes */
|
||||
length_field_len = cam_write_length_field (&buffer[3], body_length);
|
||||
buffer[3 + length_field_len] = connection->id;
|
||||
|
||||
GST_DEBUG ("writing TPDU %x connection %d", buffer[2], connection->id);
|
||||
|
||||
//cam_gst_util_dump_mem (buffer, buffer_size);
|
||||
|
||||
sret = write (tl->fd, buffer, buffer_size);
|
||||
if (sret == -1) {
|
||||
GST_ERROR ("error witing TPDU (%d): %s", errno, g_strerror (errno));
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
tl->expected_tpdus += 1;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
/* convenience function to write control TPDUs (TPDUs having a single-byte body)
|
||||
*/
|
||||
static CamReturn
|
||||
cam_tl_connection_write_control_tpdu (CamTLConnection * connection, guint8 tag)
|
||||
{
|
||||
guint8 tpdu[5];
|
||||
|
||||
/* TPDU layout (5 bytes):
|
||||
*
|
||||
* slot number (1 byte)
|
||||
* connection id (1 byte)
|
||||
* tag (1 byte)
|
||||
* length (1 byte)
|
||||
* connection id (1 byte)
|
||||
*/
|
||||
|
||||
return cam_tl_connection_write_tpdu (connection, tag, tpdu, 5, 1);
|
||||
}
|
||||
|
||||
/* read the next TPDU from the CAM */
|
||||
static CamReturn
|
||||
cam_tl_read_tpdu_next (CamTL * tl, CamTLConnection ** out_connection)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamTLConnection *connection;
|
||||
guint8 slot;
|
||||
guint8 connection_id;
|
||||
guint8 *tpdu;
|
||||
guint8 length_field_len;
|
||||
guint8 status;
|
||||
|
||||
ret = cam_tl_read (tl);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
|
||||
tpdu = tl->buffer;
|
||||
|
||||
/* must hold at least slot, connection_id, 1byte length_field, connection_id
|
||||
*/
|
||||
if (tl->buffer_size < 4) {
|
||||
GST_ERROR ("invalid TPDU length %d", tl->buffer_size);
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* LPDU slot */
|
||||
slot = tpdu[0];
|
||||
/* LPDU connection id */
|
||||
connection_id = tpdu[1];
|
||||
|
||||
connection = g_hash_table_lookup (tl->connections,
|
||||
GINT_TO_POINTER ((guint) connection_id));
|
||||
if (connection == NULL) {
|
||||
/* WHAT? */
|
||||
GST_ERROR ("CAM sent a TPDU on an unknown connection: %d", connection_id);
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* read the length_field () */
|
||||
length_field_len = cam_read_length_field (&tpdu[3], &tl->body_length);
|
||||
|
||||
if (tl->body_length + 3 > tl->buffer_size) {
|
||||
GST_ERROR ("invalid TPDU length_field (%d) exceeds "
|
||||
"the size of the buffer (%d)", tl->body_length, tl->buffer_size);
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* skip slot + connection id + tag + lenght_field () + connection id */
|
||||
tl->body = tpdu + 4 + length_field_len;
|
||||
/* do not count the connection id byte as part of the body */
|
||||
tl->body_length -= 1;
|
||||
|
||||
if (tl->buffer[tl->buffer_size - 4] != TAG_SB) {
|
||||
GST_ERROR ("no TAG_SB appended to TPDU");
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
status = tl->buffer[tl->buffer_size - 1];
|
||||
if (status & 0x80) {
|
||||
connection->has_data = TRUE;
|
||||
} else {
|
||||
connection->has_data = FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG ("received TPDU %x more data %d", tpdu[2], connection->has_data);
|
||||
tl->expected_tpdus -= 1;
|
||||
|
||||
*out_connection = connection;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
/* create a connection with the module */
|
||||
CamReturn
|
||||
cam_tl_create_connection (CamTL * tl, guint8 slot,
|
||||
CamTLConnection ** connection)
|
||||
{
|
||||
CamReturn ret;
|
||||
CamTLConnection *conn = NULL;
|
||||
|
||||
if (tl->connection_ids == 255)
|
||||
return CAM_RETURN_TRANSPORT_TOO_MANY_CONNECTIONS;
|
||||
|
||||
conn = cam_tl_connection_new (tl, ++tl->connection_ids);
|
||||
|
||||
/* send a TAG_CREATE_T_C TPDU */
|
||||
ret = cam_tl_connection_write_control_tpdu (conn, TAG_CREATE_T_C);
|
||||
if (CAM_FAILED (ret))
|
||||
goto error;
|
||||
|
||||
g_hash_table_insert (tl->connections, GINT_TO_POINTER (conn->id), conn);
|
||||
|
||||
*connection = conn;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
|
||||
error:
|
||||
if (conn)
|
||||
cam_tl_connection_destroy (conn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_tl_connection_delete (CamTLConnection * connection)
|
||||
{
|
||||
CamReturn ret;
|
||||
|
||||
ret = cam_tl_connection_write_control_tpdu (connection, TAG_DELETE_T_C);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
|
||||
connection->state = CAM_TL_CONNECTION_STATE_IN_DELETION;
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
handle_control_tpdu (CamTL * tl, CamTLConnection * connection)
|
||||
{
|
||||
if (tl->body_length != 0) {
|
||||
GST_ERROR ("got control tpdu of invalid length: %d", tl->body_length);
|
||||
return CAM_RETURN_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
switch (tl->buffer[2]) {
|
||||
/* create transport connection reply */
|
||||
case TAG_C_T_C_REPLY:
|
||||
/* a connection might be closed before it's acknowledged */
|
||||
if (connection->state != CAM_TL_CONNECTION_STATE_IN_DELETION) {
|
||||
GST_DEBUG ("connection created %d", connection->id);
|
||||
connection->state = CAM_TL_CONNECTION_STATE_OPEN;
|
||||
|
||||
if (tl->connection_created)
|
||||
tl->connection_created (tl, connection);
|
||||
}
|
||||
break;
|
||||
/* delete transport connection reply */
|
||||
case TAG_D_T_C_REPLY:
|
||||
connection->state = CAM_TL_CONNECTION_STATE_CLOSED;
|
||||
GST_DEBUG ("connection closed %d", connection->id);
|
||||
|
||||
if (tl->connection_deleted)
|
||||
tl->connection_deleted (tl, connection);
|
||||
|
||||
g_hash_table_remove (tl->connections,
|
||||
GINT_TO_POINTER ((guint) connection->id));
|
||||
break;
|
||||
}
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
handle_data_tpdu (CamTL * tl, CamTLConnection * connection)
|
||||
{
|
||||
if (tl->body_length == 0) {
|
||||
/* FIXME: figure out why this seems to happen from time to time with the
|
||||
* predator cam */
|
||||
GST_WARNING ("Empty data TPDU received");
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
if (tl->connection_data)
|
||||
return tl->connection_data (tl, connection, tl->body, tl->body_length);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
foreach_connection_get (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
GList **lst = (GList **) user_data;
|
||||
|
||||
*lst = g_list_append (*lst, value);
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_tl_connection_poll (CamTLConnection * connection, gboolean force)
|
||||
{
|
||||
CamReturn ret;
|
||||
|
||||
if (connection->last_poll == NULL) {
|
||||
connection->last_poll = g_timer_new ();
|
||||
} else if (!force &&
|
||||
g_timer_elapsed (connection->last_poll, NULL) < POLL_INTERVAL) {
|
||||
return CAM_RETURN_TRANSPORT_POLL;
|
||||
}
|
||||
|
||||
GST_DEBUG ("polling connection %d", connection->id);
|
||||
ret = cam_tl_connection_write_control_tpdu (connection, TAG_DATA_LAST);
|
||||
if (CAM_FAILED (ret))
|
||||
return ret;
|
||||
|
||||
g_timer_start (connection->last_poll);
|
||||
|
||||
return CAM_RETURN_OK;
|
||||
}
|
||||
|
||||
/* read all the queued TPDUs */
|
||||
CamReturn
|
||||
cam_tl_read_all (CamTL * tl, gboolean poll)
|
||||
{
|
||||
CamReturn ret = CAM_RETURN_OK;
|
||||
CamTLConnection *connection;
|
||||
GList *connections = NULL;
|
||||
GList *walk;
|
||||
gboolean done = FALSE;
|
||||
|
||||
while (!done) {
|
||||
while (tl->expected_tpdus) {
|
||||
/* read the next TPDU from the connection */
|
||||
ret = cam_tl_read_tpdu_next (tl, &connection);
|
||||
if (CAM_FAILED (ret)) {
|
||||
GST_ERROR ("error reading TPDU from module: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (tl->buffer[2]) {
|
||||
case TAG_C_T_C_REPLY:
|
||||
case TAG_D_T_C_REPLY:
|
||||
connection->empty_data = 0;
|
||||
ret = handle_control_tpdu (tl, connection);
|
||||
break;
|
||||
case TAG_DATA_MORE:
|
||||
case TAG_DATA_LAST:
|
||||
connection->empty_data = 0;
|
||||
ret = handle_data_tpdu (tl, connection);
|
||||
break;
|
||||
case TAG_SB:
|
||||
/* this is handled by tpdu_next */
|
||||
break;
|
||||
}
|
||||
|
||||
if (CAM_FAILED (ret))
|
||||
goto out;
|
||||
}
|
||||
|
||||
done = TRUE;
|
||||
|
||||
connections = NULL;
|
||||
g_hash_table_foreach (tl->connections,
|
||||
foreach_connection_get, &connections);
|
||||
|
||||
for (walk = connections; walk; walk = walk->next) {
|
||||
CamTLConnection *connection = CAM_TL_CONNECTION (walk->data);
|
||||
|
||||
if (connection->has_data == TRUE && connection->empty_data < 10) {
|
||||
ret = cam_tl_connection_write_control_tpdu (connection, TAG_RCV);
|
||||
if (CAM_FAILED (ret)) {
|
||||
g_list_free (connections);
|
||||
goto out;
|
||||
}
|
||||
/* increment the empty_data counter. If we get data, this will be reset
|
||||
* to 0 */
|
||||
connection->empty_data++;
|
||||
done = FALSE;
|
||||
} else if (poll) {
|
||||
ret = cam_tl_connection_poll (connection, FALSE);
|
||||
if (ret == CAM_RETURN_TRANSPORT_POLL)
|
||||
continue;
|
||||
|
||||
if (CAM_FAILED (ret)) {
|
||||
g_list_free (connections);
|
||||
goto out;
|
||||
}
|
||||
|
||||
done = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (connections);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
CamReturn
|
||||
cam_tl_connection_write (CamTLConnection * connection,
|
||||
guint8 * buffer, guint buffer_size, guint body_length)
|
||||
{
|
||||
return cam_tl_connection_write_tpdu (connection,
|
||||
TAG_DATA_LAST, buffer, buffer_size, 1 + body_length);
|
||||
}
|
115
sys/dvb/camtransport.h
Normal file
115
sys/dvb/camtransport.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* camtransport.h - GStreamer CAM (EN50221) transport layer
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_TRANSPORT_H
|
||||
#define CAM_TRANSPORT_H
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "cam.h"
|
||||
#include "camutils.h"
|
||||
|
||||
#define HOST_BUFFER_SIZE 1024
|
||||
|
||||
#define CAM_TL(obj) ((CamTL *) obj)
|
||||
#define CAM_TL_CONNECTION(obj) ((CamTLConnection *) obj)
|
||||
|
||||
typedef struct _CamTL CamTL;
|
||||
typedef struct _CamTLPrivate CamTLPrivate;
|
||||
|
||||
typedef struct _CamTLConnection CamTLConnection;
|
||||
typedef struct _CamTLConnectionPrivate CamTLConnectionPrivate;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAM_TL_CONNECTION_STATE_CLOSED,
|
||||
CAM_TL_CONNECTION_STATE_IN_CREATION,
|
||||
CAM_TL_CONNECTION_STATE_OPEN,
|
||||
CAM_TL_CONNECTION_STATE_IN_DELETION
|
||||
} CamTLConnectionState;
|
||||
|
||||
struct _CamTL
|
||||
{
|
||||
int fd;
|
||||
guint connection_ids;
|
||||
|
||||
GHashTable *connections;
|
||||
|
||||
guint expected_tpdus;
|
||||
|
||||
/* buffer containing module data */
|
||||
guint8 buffer [HOST_BUFFER_SIZE];
|
||||
/* number of bytes written in the buffer */
|
||||
guint buffer_size;
|
||||
/* index pointing to the first byte of a TPDU's body */
|
||||
guint8 *body;
|
||||
/* length of the body part */
|
||||
guint body_length;
|
||||
|
||||
/* callbacks */
|
||||
void (*request_connection) (CamTL *tl, CamTLConnection *connection);
|
||||
void (*connection_created) (CamTL *tl, CamTLConnection *connection);
|
||||
void (*connection_deleted) (CamTL *tl, CamTLConnection *connection);
|
||||
CamReturn (*connection_data) (CamTL *tl, CamTLConnection *connection,
|
||||
guint8 *data, guint length);
|
||||
|
||||
/* used by the upper layer to extend this layer */
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
struct _CamTLConnection
|
||||
{
|
||||
CamTL *tl;
|
||||
|
||||
guint8 slot;
|
||||
guint id;
|
||||
CamTLConnectionState state;
|
||||
/* TRUE if the last status byte was 0x80, FALSE otherwise */
|
||||
gboolean has_data;
|
||||
/* NCAS 1.0 sometimes reports that it has data even if it doesn't. After
|
||||
* MAX_EMPTY_DATA times that we don't get any data we assume that there's
|
||||
* actually no data.
|
||||
*/
|
||||
guint empty_data;
|
||||
/* timer restarted every time the connection is polled */
|
||||
GTimer *last_poll;
|
||||
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
CamTL *cam_tl_new (int cam_device_fd);
|
||||
void cam_tl_destroy (CamTL *tl);
|
||||
|
||||
CamReturn cam_tl_create_connection (CamTL *tl,
|
||||
guint8 slot, CamTLConnection **connnection);
|
||||
CamReturn cam_tl_connection_delete (CamTLConnection *connection);
|
||||
|
||||
void cam_tl_calc_buffer_size (CamTL *tl,
|
||||
guint body_length, guint *buffer_size, guint *offset);
|
||||
|
||||
CamReturn cam_tl_connection_write (CamTLConnection *connection,
|
||||
guint8 *data, guint buffer_size, guint body_length);
|
||||
|
||||
CamReturn cam_tl_connection_poll (CamTLConnection *connection, gboolean force);
|
||||
CamReturn cam_tl_read_all (CamTL *tl, gboolean poll);
|
||||
|
||||
#endif /* CAM_TRANSPORT_H */
|
340
sys/dvb/camutils.c
Normal file
340
sys/dvb/camutils.c
Normal file
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* camutils.c -
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cam.h"
|
||||
#include "camutils.h"
|
||||
|
||||
#define GST_CAT_DEFAULT cam_debug_cat
|
||||
|
||||
/* From the spec:
|
||||
* length_field() {
|
||||
* size_indicator
|
||||
* if (size_indicator == 0)
|
||||
* length_value
|
||||
* else if (size_indicator == 1) {
|
||||
* length_field_size
|
||||
* for (i=0; i<length_field_size; i++) {
|
||||
* length_value_byte
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
guint8
|
||||
cam_calc_length_field_size (guint length)
|
||||
{
|
||||
guint field_len;
|
||||
|
||||
if (length < G_MAXUINT8)
|
||||
field_len = 1;
|
||||
else if (length <= G_MAXUINT16)
|
||||
field_len = 3;
|
||||
else if (length <= (1 << 24) - 1)
|
||||
field_len = 4;
|
||||
else
|
||||
field_len = 5;
|
||||
|
||||
return field_len;
|
||||
}
|
||||
|
||||
/* write a length_field */
|
||||
guint8
|
||||
cam_write_length_field (guint8 * buff, guint length)
|
||||
{
|
||||
guint8 field_len = cam_calc_length_field_size (length);
|
||||
|
||||
if (buff) {
|
||||
switch (field_len) {
|
||||
case 1:
|
||||
buff[0] = length;
|
||||
break;
|
||||
case 2:
|
||||
g_return_val_if_reached (0);
|
||||
break;
|
||||
case 3:
|
||||
buff[0] = TPDU_HEADER_SIZE_INDICATOR | (field_len - 1);
|
||||
buff[1] = length >> 8;
|
||||
buff[2] = length & 0xFF;
|
||||
break;
|
||||
case 4:
|
||||
buff[0] = TPDU_HEADER_SIZE_INDICATOR | (field_len - 1);
|
||||
buff[1] = length >> 16;
|
||||
buff[2] = (length >> 8) & 0xFF;
|
||||
buff[3] = length & 0xFF;
|
||||
break;
|
||||
case 5:
|
||||
buff[0] = TPDU_HEADER_SIZE_INDICATOR | (field_len - 1);
|
||||
buff[1] = length >> 24;
|
||||
buff[2] = (length >> 16) & 0xFF;
|
||||
buff[3] = (length >> 8) & 0xFF;
|
||||
buff[4] = length & 0xFF;
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
}
|
||||
|
||||
return field_len;
|
||||
}
|
||||
|
||||
/* read a length_field */
|
||||
guint8
|
||||
cam_read_length_field (guint8 * buff, guint * length)
|
||||
{
|
||||
guint i;
|
||||
guint field_len;
|
||||
guint8 len;
|
||||
|
||||
if (buff[0] <= G_MAXINT8) {
|
||||
field_len = 1;
|
||||
len = buff[0];
|
||||
} else {
|
||||
field_len = buff[0] & ~TPDU_HEADER_SIZE_INDICATOR;
|
||||
if (field_len > 4) {
|
||||
GST_ERROR ("length_field length exceeds 4 bytes: %d", field_len);
|
||||
field_len = 0;
|
||||
len = 0;
|
||||
} else {
|
||||
len = 0;
|
||||
for (i = 0; i < field_len; ++i)
|
||||
len = (len << 8) | *++buff;
|
||||
|
||||
/* count the size indicator byte */
|
||||
field_len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (length)
|
||||
*length = len;
|
||||
|
||||
return field_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_pmt () {
|
||||
* ca_pmt_tag 24 uimsbf
|
||||
* length_field()
|
||||
* ca_pmt_list_management 8 uimsbf
|
||||
* program_number 16 uimsbf
|
||||
* reserved 2 bslbf
|
||||
* version_number 5 uimsbf
|
||||
* current_next_indicator 1 bslbf
|
||||
* reserved 4 bslbf
|
||||
* program_info_length 12 uimsbf
|
||||
* if (program_info_length != 0) {
|
||||
* ca_pmt_cmd_id at program level 8 uimsbf
|
||||
* for (i=0; i<n; i++) {
|
||||
* CA_descriptor() programme level
|
||||
* }
|
||||
* }
|
||||
* for (i=0; i<n; i++) {
|
||||
* stream_type 8 uimsbf
|
||||
* reserved 3 bslbf
|
||||
* elementary_PID elementary stream PID 13 uimsbf
|
||||
* reserved 4 bslbf
|
||||
* ES_info_length 12 uimsbf
|
||||
* if (ES_info_length != 0) {
|
||||
* ca_pmt_cmd_id at ES level 8 uimsbf
|
||||
* for (i=0; i<n; i++) {
|
||||
* CA_descriptor() elementary stream level
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
static guint
|
||||
get_ca_descriptors_length (GValueArray * descriptors)
|
||||
{
|
||||
guint i;
|
||||
guint len = 0;
|
||||
GValue *value;
|
||||
GString *desc;
|
||||
|
||||
if (descriptors != NULL) {
|
||||
for (i = 0; i < descriptors->n_values; ++i) {
|
||||
value = g_value_array_get_nth (descriptors, i);
|
||||
desc = (GString *) g_value_get_boxed (value);
|
||||
|
||||
if (desc->str[0] == 0x09)
|
||||
len += desc->len;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
write_ca_descriptors (guint8 * body, GValueArray * descriptors)
|
||||
{
|
||||
guint i;
|
||||
GValue *value;
|
||||
GString *desc;
|
||||
|
||||
if (descriptors != NULL) {
|
||||
for (i = 0; i < descriptors->n_values; ++i) {
|
||||
value = g_value_array_get_nth (descriptors, i);
|
||||
desc = (GString *) g_value_get_boxed (value);
|
||||
|
||||
if (desc->str[0] == 0x09) {
|
||||
memcpy (body, desc->str, desc->len);
|
||||
body += desc->len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
guint8 *
|
||||
cam_build_ca_pmt (GObject * pmt, guint8 list_management, guint8 cmd_id,
|
||||
guint * size)
|
||||
{
|
||||
guint body_size = 0;
|
||||
guint8 *buffer;
|
||||
guint8 *body;
|
||||
GList *lengths = NULL;
|
||||
guint len = 0;
|
||||
GValueArray *streams = NULL;
|
||||
gint program_number;
|
||||
guint version_number;
|
||||
guint i;
|
||||
GValue *value;
|
||||
GObject *stream;
|
||||
GValueArray *program_descriptors = NULL;
|
||||
GValueArray *stream_descriptors = NULL;
|
||||
|
||||
g_object_get (pmt,
|
||||
"program-number", &program_number,
|
||||
"version-number", &version_number,
|
||||
"stream-info", &streams, "descriptors", &program_descriptors, NULL);
|
||||
|
||||
/* get the length of program level CA_descriptor()s */
|
||||
len = get_ca_descriptors_length (program_descriptors);
|
||||
if (len > 0)
|
||||
/* add one byte for the program level cmd_id */
|
||||
len += 1;
|
||||
|
||||
lengths = g_list_append (lengths, GINT_TO_POINTER (len));
|
||||
body_size += 6 + len;
|
||||
|
||||
/* get the length of stream level CA_descriptor()s */
|
||||
if (streams != NULL) {
|
||||
for (i = 0; i < streams->n_values; ++i) {
|
||||
value = g_value_array_get_nth (streams, i);
|
||||
stream = g_value_get_object (value);
|
||||
|
||||
g_object_get (stream, "descriptors", &stream_descriptors, NULL);
|
||||
|
||||
len = get_ca_descriptors_length (stream_descriptors);
|
||||
if (len > 0)
|
||||
/* one byte for the stream level cmd_id */
|
||||
len += 1;
|
||||
|
||||
lengths = g_list_append (lengths, GINT_TO_POINTER (len));
|
||||
body_size += 5 + len;
|
||||
|
||||
if (stream_descriptors) {
|
||||
g_value_array_free (stream_descriptors);
|
||||
stream_descriptors = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer = g_malloc0 (body_size);
|
||||
body = buffer;
|
||||
|
||||
/*
|
||||
guint length_field_len = cam_calc_length_field_size (body_size);
|
||||
guint apdu_header_length = 3 + length_field_len;
|
||||
guint8 *apdu = (buffer + buffer_size) - body_size - apdu_header_length;
|
||||
apdu [0] = 0x9F;
|
||||
apdu [1] = 0x80;
|
||||
apdu [2] = 0x32;
|
||||
|
||||
g_print ("LEN %d %d", length_field_len, body_size);
|
||||
|
||||
cam_write_length_field (&apdu [3], body_size);
|
||||
body += 4;
|
||||
*/
|
||||
|
||||
*body++ = list_management;
|
||||
|
||||
GST_WRITE_UINT16_BE (body, program_number);
|
||||
body += 2;
|
||||
|
||||
*body++ = (version_number << 1) | 0x01;
|
||||
|
||||
len = GPOINTER_TO_INT (lengths->data);
|
||||
lengths = g_list_delete_link (lengths, lengths);
|
||||
GST_WRITE_UINT16_BE (body, len);
|
||||
body += 2;
|
||||
|
||||
if (len != 0) {
|
||||
*body++ = cmd_id;
|
||||
|
||||
body = write_ca_descriptors (body, program_descriptors);
|
||||
}
|
||||
|
||||
if (program_descriptors)
|
||||
g_value_array_free (program_descriptors);
|
||||
|
||||
for (i = 0; i < streams->n_values; ++i) {
|
||||
guint stream_type;
|
||||
guint stream_pid;
|
||||
|
||||
value = g_value_array_get_nth (streams, i);
|
||||
stream = g_value_get_object (value);
|
||||
|
||||
g_object_get (stream,
|
||||
"stream-type", &stream_type,
|
||||
"pid", &stream_pid, "descriptors", &stream_descriptors, NULL);
|
||||
|
||||
*body++ = stream_type;
|
||||
GST_WRITE_UINT16_BE (body, stream_pid);
|
||||
body += 2;
|
||||
len = GPOINTER_TO_INT (lengths->data);
|
||||
lengths = g_list_delete_link (lengths, lengths);
|
||||
GST_WRITE_UINT16_BE (body, len);
|
||||
body += 2;
|
||||
|
||||
if (len != 0) {
|
||||
*body++ = cmd_id;
|
||||
body = write_ca_descriptors (body, stream_descriptors);
|
||||
}
|
||||
|
||||
if (stream_descriptors) {
|
||||
g_value_array_free (stream_descriptors);
|
||||
stream_descriptors = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (streams)
|
||||
g_value_array_free (streams);
|
||||
|
||||
*size = body_size;
|
||||
return buffer;
|
||||
}
|
59
sys/dvb/camutils.h
Normal file
59
sys/dvb/camutils.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* camutils.h - GStreamer CAM (EN50221) support
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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 CAM_UTILS_H
|
||||
#define CAM_UTILS_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#define TPDU_HEADER_SIZE_INDICATOR 0x80
|
||||
|
||||
#define CAM_FAILED(ret) (ret <= CAM_RETURN_ERROR)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* generic */
|
||||
CAM_RETURN_OK = 0,
|
||||
CAM_RETURN_ERROR = -1,
|
||||
|
||||
/* transport specific */
|
||||
CAM_RETURN_TRANSPORT_ERROR = -10,
|
||||
CAM_RETURN_TRANSPORT_TOO_MANY_CONNECTIONS = -11,
|
||||
CAM_RETURN_TRANSPORT_TIMEOUT = -12,
|
||||
CAM_RETURN_TRANSPORT_POLL = -13,
|
||||
|
||||
/* session specific */
|
||||
CAM_RETURN_SESSION_ERROR = -30,
|
||||
CAM_RETURN_SESSION_TOO_MANY_SESSIONS = -31,
|
||||
|
||||
/* application specific */
|
||||
CAM_RETURN_APPLICATION_ERROR = -40,
|
||||
} CamReturn;
|
||||
|
||||
guint8 cam_calc_length_field_size (guint length);
|
||||
guint8 cam_write_length_field (guint8 *buff, guint length);
|
||||
guint8 cam_read_length_field (guint8 *buff, guint *length);
|
||||
guint8 *cam_build_ca_pmt (GObject *pmt, guint8 list_management, guint8 cmd_id, guint *size);
|
||||
|
||||
#endif /* CAM_UTILS_H */
|
897
sys/dvb/dvbbasebin.c
Normal file
897
sys/dvb/dvbbasebin.c
Normal file
|
@ -0,0 +1,897 @@
|
|||
/*
|
||||
* dvbbasebin.c -
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include "dvbbasebin.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (dvb_base_bin_debug);
|
||||
#define GST_CAT_DEFAULT dvb_base_bin_debug
|
||||
|
||||
static GstElementDetails dvb_base_bin_details = GST_ELEMENT_DETAILS ("DVB bin",
|
||||
"Source/Bin/Video",
|
||||
"Access descramble and split DVB streams",
|
||||
"Alessandro Decina <alessandro@nnva.org>");
|
||||
|
||||
static GstStaticPadTemplate src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
|
||||
);
|
||||
|
||||
static GstStaticPadTemplate program_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("program_%d", GST_PAD_SRC,
|
||||
GST_PAD_SOMETIMES,
|
||||
GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
|
||||
);
|
||||
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
PROP_ADAPTER,
|
||||
PROP_FRONTEND,
|
||||
PROP_FREQUENCY,
|
||||
PROP_POLARITY,
|
||||
PROP_SYMBOL_RATE,
|
||||
PROP_BANDWIDTH,
|
||||
PROP_CODE_RATE_HP,
|
||||
PROP_CODE_RATE_LP,
|
||||
PROP_GUARD,
|
||||
PROP_MODULATION,
|
||||
PROP_TRANS_MODE,
|
||||
PROP_HIERARCHY,
|
||||
PROP_INVERSION,
|
||||
PROP_PROGRAM_NUMBERS,
|
||||
PROP_STATS_REPORTING_INTERVAL
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint16 pid;
|
||||
guint usecount;
|
||||
} DvbBaseBinStream;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint program_number;
|
||||
guint16 pmt_pid;
|
||||
guint16 pcr_pid;
|
||||
GObject *pmt;
|
||||
GObject *old_pmt;
|
||||
gboolean selected;
|
||||
gboolean pmt_active;
|
||||
gboolean active;
|
||||
GstPad *ghost;
|
||||
} DvbBaseBinProgram;
|
||||
|
||||
static void dvb_base_bin_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void dvb_base_bin_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void dvb_base_bin_dispose (GObject * object);
|
||||
static void dvb_base_bin_finalize (GObject * object);
|
||||
|
||||
static gboolean dvb_base_bin_ts_pad_probe_cb (GstPad * pad,
|
||||
GstBuffer * buf, gpointer user_data);
|
||||
static GstStateChangeReturn dvb_base_bin_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
static void dvb_base_bin_pat_info_changed_cb (GstElement * mpegtsparse,
|
||||
GParamSpec * pspec, DvbBaseBin * dvbbasebin);
|
||||
static void dvb_base_bin_pmt_info_cb (GstElement * mpegtsparse,
|
||||
guint program_number, GObject * pmt, DvbBaseBin * dvbbasebin);
|
||||
static void dvb_base_bin_pad_added_cb (GstElement * mpegtsparse,
|
||||
GstPad * pad, DvbBaseBin * dvbbasebin);
|
||||
static void dvb_base_bin_pad_removed_cb (GstElement * mpegtsparse,
|
||||
GstPad * pad, DvbBaseBin * dvbbasebin);
|
||||
static GstPad *dvb_base_bin_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name);
|
||||
static void dvb_base_bin_release_pad (GstElement * element, GstPad * pad);
|
||||
|
||||
static DvbBaseBinStream *
|
||||
dvb_base_bin_add_stream (DvbBaseBin * dvbbasebin, guint16 pid)
|
||||
{
|
||||
DvbBaseBinStream *stream;
|
||||
|
||||
stream = g_new0 (DvbBaseBinStream, 1);
|
||||
stream->pid = pid;
|
||||
stream->usecount = 0;
|
||||
|
||||
g_hash_table_insert (dvbbasebin->streams,
|
||||
GINT_TO_POINTER ((gint) pid), stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static DvbBaseBinStream *
|
||||
dvb_base_bin_get_stream (DvbBaseBin * dvbbasebin, guint16 pid)
|
||||
{
|
||||
return (DvbBaseBinStream *) g_hash_table_lookup (dvbbasebin->streams,
|
||||
GINT_TO_POINTER ((gint) pid));
|
||||
}
|
||||
|
||||
static DvbBaseBinProgram *
|
||||
dvb_base_bin_add_program (DvbBaseBin * dvbbasebin, gint program_number)
|
||||
{
|
||||
DvbBaseBinProgram *program;
|
||||
|
||||
program = g_new0 (DvbBaseBinProgram, 1);
|
||||
program->program_number = program_number;
|
||||
program->selected = FALSE;
|
||||
program->active = FALSE;
|
||||
program->pmt_pid = G_MAXUINT16;
|
||||
program->pcr_pid = G_MAXUINT16;
|
||||
program->pmt = NULL;
|
||||
program->old_pmt = NULL;
|
||||
|
||||
g_hash_table_insert (dvbbasebin->programs,
|
||||
GINT_TO_POINTER (program_number), program);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
static DvbBaseBinProgram *
|
||||
dvb_base_bin_get_program (DvbBaseBin * dvbbasebin, gint program_number)
|
||||
{
|
||||
return (DvbBaseBinProgram *) g_hash_table_lookup (dvbbasebin->programs,
|
||||
GINT_TO_POINTER (program_number));
|
||||
}
|
||||
|
||||
/*
|
||||
static guint signals [LAST_SIGNAL] = { 0 };
|
||||
*/
|
||||
|
||||
GST_BOILERPLATE (DvbBaseBin, dvb_base_bin, GstBin, GST_TYPE_BIN);
|
||||
|
||||
static void
|
||||
dvb_base_bin_base_init (gpointer klass)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
element_class->request_new_pad = dvb_base_bin_request_new_pad;
|
||||
element_class->release_pad = dvb_base_bin_release_pad;
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&program_template));
|
||||
|
||||
gst_element_class_set_details (element_class, &dvb_base_bin_details);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_class_init (DvbBaseBinClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *element_class;
|
||||
GstElementFactory *dvbsrc_factory;
|
||||
GObjectClass *dvbsrc_class;
|
||||
typedef struct
|
||||
{
|
||||
guint prop_id;
|
||||
const gchar *prop_name;
|
||||
} ProxyedProperty;
|
||||
ProxyedProperty *walk;
|
||||
ProxyedProperty proxyed_properties[] = {
|
||||
{PROP_ADAPTER, "adapter"},
|
||||
{PROP_FRONTEND, "frontend"},
|
||||
{PROP_FREQUENCY, "frequency"},
|
||||
{PROP_POLARITY, "polarity"},
|
||||
{PROP_SYMBOL_RATE, "symbol-rate"},
|
||||
{PROP_BANDWIDTH, "bandwidth"},
|
||||
{PROP_CODE_RATE_HP, "code-rate-hp"},
|
||||
{PROP_CODE_RATE_LP, "code-rate-lp"},
|
||||
{PROP_GUARD, "guard"},
|
||||
{PROP_MODULATION, "modulation"},
|
||||
{PROP_TRANS_MODE, "trans-mode"},
|
||||
{PROP_HIERARCHY, "hierarchy"},
|
||||
{PROP_INVERSION, "inversion"},
|
||||
{PROP_STATS_REPORTING_INTERVAL, "stats-reporting-interval"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
element_class = GST_ELEMENT_CLASS (klass);
|
||||
element_class->change_state = dvb_base_bin_change_state;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->set_property = dvb_base_bin_set_property;
|
||||
gobject_class->get_property = dvb_base_bin_get_property;
|
||||
gobject_class->dispose = dvb_base_bin_dispose;
|
||||
gobject_class->finalize = dvb_base_bin_finalize;
|
||||
|
||||
/* install dvbsrc properties */
|
||||
dvbsrc_factory = gst_element_factory_find ("dvbsrc");
|
||||
dvbsrc_class = g_type_class_ref (dvbsrc_factory->type);
|
||||
walk = proxyed_properties;
|
||||
while (walk->prop_name != NULL) {
|
||||
GParamSpec *pspec;
|
||||
GParamSpec *our_pspec;
|
||||
|
||||
pspec = g_object_class_find_property (dvbsrc_class, walk->prop_name);
|
||||
if (pspec != NULL) {
|
||||
GType param_type = G_PARAM_SPEC_TYPE (pspec);
|
||||
|
||||
if (param_type == G_TYPE_PARAM_INT) {
|
||||
GParamSpecInt *src_pspec = G_PARAM_SPEC_INT (pspec);
|
||||
|
||||
our_pspec = g_param_spec_int (g_param_spec_get_name (pspec),
|
||||
g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
|
||||
src_pspec->minimum, src_pspec->maximum, src_pspec->default_value,
|
||||
pspec->flags);
|
||||
} else if (param_type == G_TYPE_PARAM_UINT) {
|
||||
GParamSpecUInt *src_pspec = G_PARAM_SPEC_UINT (pspec);
|
||||
|
||||
our_pspec = g_param_spec_uint (g_param_spec_get_name (pspec),
|
||||
g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
|
||||
src_pspec->minimum, src_pspec->maximum, src_pspec->default_value,
|
||||
pspec->flags);
|
||||
} else if (param_type == G_TYPE_PARAM_STRING) {
|
||||
GParamSpecString *src_pspec = G_PARAM_SPEC_STRING (pspec);
|
||||
|
||||
our_pspec = g_param_spec_string (g_param_spec_get_name (pspec),
|
||||
g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
|
||||
src_pspec->default_value, pspec->flags);
|
||||
} else if (param_type == G_TYPE_PARAM_ENUM) {
|
||||
GParamSpecEnum *src_pspec = G_PARAM_SPEC_ENUM (pspec);
|
||||
|
||||
our_pspec = g_param_spec_enum (g_param_spec_get_name (pspec),
|
||||
g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
|
||||
pspec->value_type, src_pspec->default_value, pspec->flags);
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
g_object_class_install_property (gobject_class, walk->prop_id, our_pspec);
|
||||
} else {
|
||||
g_warning ("dvbsrc has no property named %s", walk->prop_name);
|
||||
}
|
||||
++walk;
|
||||
}
|
||||
g_type_class_unref (dvbsrc_class);
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBERS,
|
||||
g_param_spec_string ("program-numbers",
|
||||
"Program Numbers",
|
||||
"Colon separated list of programs", "", G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_reset (DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
if (dvbbasebin->hwcam) {
|
||||
cam_device_close (dvbbasebin->hwcam);
|
||||
cam_device_free (dvbbasebin->hwcam);
|
||||
dvbbasebin->hwcam = NULL;
|
||||
}
|
||||
|
||||
if (dvbbasebin->ts_pad) {
|
||||
gst_element_release_request_pad (GST_ELEMENT (dvbbasebin->mpegtsparse),
|
||||
dvbbasebin->ts_pad);
|
||||
dvbbasebin->ts_pad = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_init (DvbBaseBin * dvbbasebin, DvbBaseBinClass * klass)
|
||||
{
|
||||
dvbbasebin->dvbsrc = gst_element_factory_make ("dvbsrc", NULL);
|
||||
dvbbasebin->buffer_queue = gst_element_factory_make ("queue", NULL);
|
||||
dvbbasebin->mpegtsparse = gst_element_factory_make ("mpegtsparse", NULL);
|
||||
g_object_connect (dvbbasebin->mpegtsparse,
|
||||
"signal::notify::pat-info", dvb_base_bin_pat_info_changed_cb, dvbbasebin,
|
||||
"signal::pmt-info", dvb_base_bin_pmt_info_cb, dvbbasebin,
|
||||
"signal::pad-added", dvb_base_bin_pad_added_cb, dvbbasebin,
|
||||
"signal::pad-removed", dvb_base_bin_pad_removed_cb, dvbbasebin, NULL);
|
||||
|
||||
gst_bin_add_many (GST_BIN (dvbbasebin), dvbbasebin->dvbsrc,
|
||||
dvbbasebin->buffer_queue, dvbbasebin->mpegtsparse, NULL);
|
||||
|
||||
gst_element_link_many (dvbbasebin->dvbsrc,
|
||||
dvbbasebin->buffer_queue, dvbbasebin->mpegtsparse, NULL);
|
||||
|
||||
dvbbasebin->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, g_free);
|
||||
dvbbasebin->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, g_free);
|
||||
|
||||
dvbbasebin->pmtlist = NULL;
|
||||
dvbbasebin->pmtlist_changed = FALSE;
|
||||
|
||||
dvbbasebin->disposed = FALSE;
|
||||
dvb_base_bin_reset (dvbbasebin);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_dispose (GObject * object)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin = GST_DVB_BASE_BIN (object);
|
||||
|
||||
if (!dvbbasebin->disposed) {
|
||||
/* remove mpegtsparse BEFORE dvbsrc, since the mpegtsparse::pad-removed
|
||||
* signal handler uses dvbsrc */
|
||||
dvb_base_bin_reset (dvbbasebin);
|
||||
gst_bin_remove (GST_BIN (dvbbasebin), dvbbasebin->mpegtsparse);
|
||||
gst_bin_remove (GST_BIN (dvbbasebin), dvbbasebin->dvbsrc);
|
||||
gst_bin_remove (GST_BIN (dvbbasebin), dvbbasebin->buffer_queue);
|
||||
dvbbasebin->disposed = TRUE;
|
||||
}
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->dispose)
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_finalize (GObject * object)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin = GST_DVB_BASE_BIN (object);
|
||||
|
||||
g_hash_table_destroy (dvbbasebin->streams);
|
||||
g_hash_table_destroy (dvbbasebin->programs);
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin = GST_DVB_BASE_BIN (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ADAPTER:
|
||||
case PROP_FRONTEND:
|
||||
case PROP_FREQUENCY:
|
||||
case PROP_POLARITY:
|
||||
case PROP_SYMBOL_RATE:
|
||||
case PROP_BANDWIDTH:
|
||||
case PROP_CODE_RATE_HP:
|
||||
case PROP_CODE_RATE_LP:
|
||||
case PROP_GUARD:
|
||||
case PROP_MODULATION:
|
||||
case PROP_TRANS_MODE:
|
||||
case PROP_HIERARCHY:
|
||||
case PROP_INVERSION:
|
||||
case PROP_STATS_REPORTING_INTERVAL:
|
||||
/* FIXME: check if we can tune (state < PLAYING || program-numbers == "") */
|
||||
g_object_set_property (G_OBJECT (dvbbasebin->dvbsrc), pspec->name, value);
|
||||
break;
|
||||
case PROP_PROGRAM_NUMBERS:
|
||||
g_object_set_property (G_OBJECT (dvbbasebin->mpegtsparse), pspec->name,
|
||||
value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin = GST_DVB_BASE_BIN (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ADAPTER:
|
||||
case PROP_FRONTEND:
|
||||
case PROP_FREQUENCY:
|
||||
case PROP_POLARITY:
|
||||
case PROP_SYMBOL_RATE:
|
||||
case PROP_BANDWIDTH:
|
||||
case PROP_CODE_RATE_HP:
|
||||
case PROP_CODE_RATE_LP:
|
||||
case PROP_GUARD:
|
||||
case PROP_MODULATION:
|
||||
case PROP_TRANS_MODE:
|
||||
case PROP_HIERARCHY:
|
||||
case PROP_INVERSION:
|
||||
case PROP_STATS_REPORTING_INTERVAL:
|
||||
g_object_get_property (G_OBJECT (dvbbasebin->dvbsrc), pspec->name, value);
|
||||
break;
|
||||
case PROP_PROGRAM_NUMBERS:
|
||||
g_object_get_property (G_OBJECT (dvbbasebin->mpegtsparse), pspec->name,
|
||||
value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
dvb_base_bin_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name)
|
||||
{
|
||||
GstPad *pad;
|
||||
GstPad *ghost;
|
||||
gchar *pad_name;
|
||||
|
||||
if (name == NULL)
|
||||
name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
|
||||
|
||||
pad =
|
||||
gst_element_get_request_pad (GST_DVB_BASE_BIN (element)->mpegtsparse,
|
||||
name);
|
||||
if (pad == NULL)
|
||||
return NULL;
|
||||
|
||||
pad_name = gst_pad_get_name (pad);
|
||||
ghost = gst_ghost_pad_new (pad_name, pad);
|
||||
g_free (pad_name);
|
||||
gst_element_add_pad (element, ghost);
|
||||
|
||||
return ghost;
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_release_pad (GstElement * element, GstPad * pad)
|
||||
{
|
||||
GstGhostPad *ghost;
|
||||
GstPad *target;
|
||||
|
||||
g_return_if_fail (GST_IS_DVB_BASE_BIN (element));
|
||||
|
||||
ghost = GST_GHOST_PAD (pad);
|
||||
target = gst_ghost_pad_get_target (ghost);
|
||||
gst_element_release_request_pad (GST_ELEMENT (GST_DVB_BASE_BIN (element)->
|
||||
mpegtsparse), target);
|
||||
gst_object_unref (target);
|
||||
|
||||
gst_element_remove_pad (element, pad);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_reset_pmtlist (DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
CamConditionalAccessPmtFlag flag;
|
||||
GList *walk;
|
||||
GObject *pmt;
|
||||
|
||||
walk = dvbbasebin->pmtlist;
|
||||
while (walk) {
|
||||
if (walk->prev == NULL) {
|
||||
if (walk->next == NULL)
|
||||
flag = CAM_CONDITIONAL_ACCESS_PMT_FLAG_ONLY;
|
||||
else
|
||||
flag = CAM_CONDITIONAL_ACCESS_PMT_FLAG_FIRST;
|
||||
} else {
|
||||
if (walk->next == NULL)
|
||||
flag = CAM_CONDITIONAL_ACCESS_PMT_FLAG_LAST;
|
||||
else
|
||||
flag = CAM_CONDITIONAL_ACCESS_PMT_FLAG_MORE;
|
||||
}
|
||||
|
||||
pmt = G_OBJECT (walk->data);
|
||||
cam_device_set_pmt (dvbbasebin->hwcam, pmt, flag);
|
||||
|
||||
walk = walk->next;
|
||||
}
|
||||
|
||||
dvbbasebin->pmtlist_changed = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dvb_base_bin_ts_pad_probe_cb (GstPad * pad, GstBuffer * buf, gpointer user_data)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin = GST_DVB_BASE_BIN (user_data);
|
||||
|
||||
if (dvbbasebin->hwcam) {
|
||||
cam_device_poll (dvbbasebin->hwcam);
|
||||
|
||||
if (dvbbasebin->pmtlist_changed) {
|
||||
if (cam_device_ready (dvbbasebin->hwcam)) {
|
||||
GST_DEBUG_OBJECT (dvbbasebin, "pmt list changed");
|
||||
dvb_base_bin_reset_pmtlist (dvbbasebin);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (dvbbasebin, "pmt list changed but CAM not ready");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_init_cam (DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
gint adapter;
|
||||
gchar *ca_file;
|
||||
|
||||
g_object_get (dvbbasebin->dvbsrc, "adapter", &adapter, NULL);
|
||||
/* TODO: handle multiple cams */
|
||||
ca_file = g_strdup_printf ("/dev/dvb/adapter%d/ca0", adapter);
|
||||
if (g_file_test (ca_file, G_FILE_TEST_EXISTS)) {
|
||||
dvbbasebin->hwcam = cam_device_new ();
|
||||
if (cam_device_open (dvbbasebin->hwcam, ca_file)) {
|
||||
/* HACK: poll the cam in a buffer probe */
|
||||
dvbbasebin->ts_pad =
|
||||
gst_element_get_request_pad (dvbbasebin->mpegtsparse, "src%d");
|
||||
gst_pad_add_buffer_probe (dvbbasebin->ts_pad,
|
||||
G_CALLBACK (dvb_base_bin_ts_pad_probe_cb), dvbbasebin);
|
||||
} else {
|
||||
GST_ERROR_OBJECT (dvbbasebin, "could not open %s", ca_file);
|
||||
cam_device_free (dvbbasebin->hwcam);
|
||||
dvbbasebin->hwcam = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (ca_file);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
dvb_base_bin_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin;
|
||||
GstStateChangeReturn ret;
|
||||
|
||||
dvbbasebin = GST_DVB_BASE_BIN (element);
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
dvb_base_bin_init_cam (dvbbasebin);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
dvb_base_bin_reset (dvbbasebin);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
foreach_stream_build_filter (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
DvbBaseBin *dvbbasebin = GST_DVB_BASE_BIN (user_data);
|
||||
DvbBaseBinStream *stream = (DvbBaseBinStream *) value;
|
||||
gchar *tmp, *pid;
|
||||
|
||||
g_assert (stream->usecount >= 0);
|
||||
|
||||
GST_DEBUG ("stream %d usecount %d", stream->pid, stream->usecount);
|
||||
|
||||
if (stream->usecount > 0) {
|
||||
/* TODO: use g_strjoinv FTW */
|
||||
tmp = dvbbasebin->filter;
|
||||
pid = g_strdup_printf ("%d", stream->pid);
|
||||
dvbbasebin->filter = g_strjoin (":", pid, dvbbasebin->filter, NULL);
|
||||
|
||||
g_free (pid);
|
||||
g_free (tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_rebuild_filter (DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
g_hash_table_foreach (dvbbasebin->streams,
|
||||
foreach_stream_build_filter, dvbbasebin);
|
||||
|
||||
if (dvbbasebin->filter == NULL)
|
||||
/* fix dvbsrc to handle NULL filter */
|
||||
dvbbasebin->filter = g_strdup ("");
|
||||
|
||||
GST_INFO_OBJECT (dvbbasebin, "rebuilt filter %s", dvbbasebin->filter);
|
||||
|
||||
/* FIXME: disable this until we find a way to filter out unwanted pids
|
||||
g_object_set (dvbbasebin->dvbsrc, "pids", dvbbasebin->filter, NULL);
|
||||
*/
|
||||
g_free (dvbbasebin->filter);
|
||||
dvbbasebin->filter = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_remove_pmt_streams (DvbBaseBin * dvbbasebin, GObject * pmt)
|
||||
{
|
||||
GValueArray *streams;
|
||||
gint program_number;
|
||||
gint i;
|
||||
GValue *value;
|
||||
GObject *streamobj;
|
||||
DvbBaseBinStream *stream;
|
||||
guint pid;
|
||||
guint stream_type;
|
||||
|
||||
g_object_get (pmt, "program-number", &program_number,
|
||||
"stream-info", &streams, NULL);
|
||||
|
||||
for (i = 0; i < streams->n_values; ++i) {
|
||||
value = g_value_array_get_nth (streams, i);
|
||||
streamobj = g_value_get_object (value);
|
||||
|
||||
g_object_get (streamobj, "pid", &pid, "stream-type", &stream_type, NULL);
|
||||
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, (guint16) pid);
|
||||
if (stream == NULL) {
|
||||
GST_WARNING_OBJECT (dvbbasebin, "removing unknown stream %d ??", pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
--stream->usecount;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_add_pmt_streams (DvbBaseBin * dvbbasebin, GObject * pmt)
|
||||
{
|
||||
DvbBaseBinStream *stream;
|
||||
GValueArray *streams;
|
||||
gint program_number;
|
||||
gint i;
|
||||
GValue *value;
|
||||
GObject *streamobj;
|
||||
guint pid;
|
||||
guint stream_type;
|
||||
|
||||
g_object_get (pmt, "program-number", &program_number,
|
||||
"stream-info", &streams, NULL);
|
||||
|
||||
for (i = 0; i < streams->n_values; ++i) {
|
||||
value = g_value_array_get_nth (streams, i);
|
||||
streamobj = g_value_get_object (value);
|
||||
|
||||
g_object_get (streamobj, "pid", &pid, "stream-type", &stream_type, NULL);
|
||||
GST_DEBUG ("filtering stream %d stream_type %d", pid, stream_type);
|
||||
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, (guint16) pid);
|
||||
if (stream == NULL)
|
||||
stream = dvb_base_bin_add_stream (dvbbasebin, (guint16) pid);
|
||||
|
||||
++stream->usecount;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_activate_program (DvbBaseBin * dvbbasebin,
|
||||
DvbBaseBinProgram * program)
|
||||
{
|
||||
DvbBaseBinStream *stream;
|
||||
guint pid;
|
||||
|
||||
if (program->old_pmt) {
|
||||
dvb_base_bin_remove_pmt_streams (dvbbasebin, program->old_pmt);
|
||||
dvbbasebin->pmtlist = g_list_remove (dvbbasebin->pmtlist, program->old_pmt);
|
||||
}
|
||||
|
||||
/* activate the PMT and PCR streams. If the PCR stream is in the PMT its
|
||||
* usecount will be incremented by 2 here and decremented by 2 when the
|
||||
* program is deactivated */
|
||||
if (!program->pmt_active) {
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, program->pmt_pid);
|
||||
if (stream == NULL)
|
||||
stream = dvb_base_bin_add_stream (dvbbasebin, program->pmt_pid);
|
||||
stream->usecount += 1;
|
||||
program->pmt_active = TRUE;
|
||||
}
|
||||
|
||||
if (program->pmt) {
|
||||
guint16 old_pcr_pid;
|
||||
|
||||
old_pcr_pid = program->pcr_pid;
|
||||
g_object_get (program->pmt, "pcr-pid", &pid, NULL);
|
||||
program->pcr_pid = pid;
|
||||
if (old_pcr_pid != G_MAXUINT16 && old_pcr_pid != program->pcr_pid)
|
||||
dvb_base_bin_get_stream (dvbbasebin, old_pcr_pid)->usecount--;
|
||||
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, program->pcr_pid);
|
||||
if (stream == NULL)
|
||||
stream = dvb_base_bin_add_stream (dvbbasebin, program->pcr_pid);
|
||||
stream->usecount += 1;
|
||||
|
||||
dvb_base_bin_add_pmt_streams (dvbbasebin, program->pmt);
|
||||
dvbbasebin->pmtlist = g_list_append (dvbbasebin->pmtlist, program->pmt);
|
||||
dvbbasebin->pmtlist_changed = TRUE;
|
||||
program->active = TRUE;
|
||||
}
|
||||
|
||||
dvb_base_bin_rebuild_filter (dvbbasebin);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_deactivate_program (DvbBaseBin * dvbbasebin,
|
||||
DvbBaseBinProgram * program)
|
||||
{
|
||||
DvbBaseBinStream *stream;
|
||||
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, program->pmt_pid);
|
||||
if (stream != NULL)
|
||||
stream->usecount -= 1;
|
||||
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, program->pcr_pid);
|
||||
if (stream != NULL)
|
||||
stream->usecount -= 1;
|
||||
|
||||
if (program->pmt) {
|
||||
dvb_base_bin_remove_pmt_streams (dvbbasebin, program->pmt);
|
||||
dvbbasebin->pmtlist = g_list_remove (dvbbasebin->pmtlist, program->pmt);
|
||||
dvbbasebin->pmtlist_changed = TRUE;
|
||||
}
|
||||
|
||||
dvb_base_bin_rebuild_filter (dvbbasebin);
|
||||
program->pmt_active = FALSE;
|
||||
program->active = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_pat_info_changed_cb (GstElement * mpegtsparse,
|
||||
GParamSpec * pspec, DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
DvbBaseBinProgram *program;
|
||||
DvbBaseBinStream *stream;
|
||||
GValueArray *pat_info;
|
||||
GValue *value;
|
||||
GObject *program_info;
|
||||
gint program_number;
|
||||
guint pid;
|
||||
guint16 old_pmt_pid;
|
||||
gint i;
|
||||
gboolean rebuild_filter = FALSE;
|
||||
|
||||
g_object_get (mpegtsparse, "pat-info", &pat_info, NULL);
|
||||
|
||||
for (i = 0; i < pat_info->n_values; ++i) {
|
||||
value = g_value_array_get_nth (pat_info, i);
|
||||
program_info = g_value_get_object (value);
|
||||
|
||||
g_object_get (program_info, "program-number", &program_number,
|
||||
"pid", &pid, NULL);
|
||||
|
||||
program = dvb_base_bin_get_program (dvbbasebin, program_number);
|
||||
if (program == NULL)
|
||||
program = dvb_base_bin_add_program (dvbbasebin, program_number);
|
||||
|
||||
old_pmt_pid = program->pmt_pid;
|
||||
program->pmt_pid = pid;
|
||||
|
||||
if (program->selected) {
|
||||
/* PAT update */
|
||||
if (old_pmt_pid != G_MAXUINT16 && old_pmt_pid != program->pmt_pid)
|
||||
dvb_base_bin_get_stream (dvbbasebin, old_pmt_pid)->usecount -= 1;
|
||||
|
||||
stream = dvb_base_bin_get_stream (dvbbasebin, program->pmt_pid);
|
||||
if (stream == NULL)
|
||||
stream = dvb_base_bin_add_stream (dvbbasebin, program->pmt_pid);
|
||||
|
||||
stream->usecount += 1;
|
||||
|
||||
rebuild_filter = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_value_array_free (pat_info);
|
||||
|
||||
if (rebuild_filter)
|
||||
dvb_base_bin_rebuild_filter (dvbbasebin);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_pmt_info_cb (GstElement * mpegtsparse,
|
||||
guint program_number, GObject * pmt, DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
DvbBaseBinProgram *program;
|
||||
|
||||
program = dvb_base_bin_get_program (dvbbasebin, program_number);
|
||||
if (program == NULL) {
|
||||
GST_WARNING ("got PMT for program %d but program not in PAT",
|
||||
program_number);
|
||||
program = dvb_base_bin_add_program (dvbbasebin, program_number);
|
||||
}
|
||||
|
||||
program->old_pmt = program->pmt;
|
||||
program->pmt = g_object_ref (pmt);
|
||||
|
||||
/* activate the program if it's selected and either it's not active or its pmt
|
||||
* changed */
|
||||
if (program->selected && (!program->active || program->old_pmt != NULL))
|
||||
dvb_base_bin_activate_program (dvbbasebin, program);
|
||||
|
||||
if (program->old_pmt) {
|
||||
g_object_unref (program->old_pmt);
|
||||
program->old_pmt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
get_pad_program_number (GstPad * pad)
|
||||
{
|
||||
gchar *progstr;
|
||||
gchar *name;
|
||||
|
||||
name = gst_pad_get_name (pad);
|
||||
|
||||
if (strncmp (name, "program_", 8) != 0) {
|
||||
g_free (name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
progstr = strstr (name, "_");
|
||||
g_free (name);
|
||||
if (progstr == NULL)
|
||||
return -1;
|
||||
|
||||
return strtol (++progstr, NULL, 10);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_pad_added_cb (GstElement * mpegtsparse,
|
||||
GstPad * pad, DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
DvbBaseBinProgram *program;
|
||||
gint program_number;
|
||||
|
||||
program_number = get_pad_program_number (pad);
|
||||
if (program_number == -1)
|
||||
return;
|
||||
|
||||
program = dvb_base_bin_get_program (dvbbasebin, program_number);
|
||||
if (program == NULL)
|
||||
program = dvb_base_bin_add_program (dvbbasebin, program_number);
|
||||
program->selected = TRUE;
|
||||
program->ghost = gst_ghost_pad_new (gst_pad_get_name (pad), pad);
|
||||
gst_pad_set_active (program->ghost, TRUE);
|
||||
gst_element_add_pad (GST_ELEMENT (dvbbasebin), program->ghost);
|
||||
|
||||
/* if the program has a pmt, activate it now, otherwise it will get activated
|
||||
* when there's a PMT */
|
||||
if (!program->active && program->pmt_pid != G_MAXUINT16)
|
||||
dvb_base_bin_activate_program (dvbbasebin, program);
|
||||
}
|
||||
|
||||
static void
|
||||
dvb_base_bin_pad_removed_cb (GstElement * mpegtsparse,
|
||||
GstPad * pad, DvbBaseBin * dvbbasebin)
|
||||
{
|
||||
DvbBaseBinProgram *program;
|
||||
gint program_number;
|
||||
|
||||
program_number = get_pad_program_number (pad);
|
||||
if (program_number == -1)
|
||||
return;
|
||||
|
||||
program = dvb_base_bin_get_program (dvbbasebin, program_number);
|
||||
program->selected = FALSE;
|
||||
dvb_base_bin_deactivate_program (dvbbasebin, program);
|
||||
gst_element_remove_pad (GST_ELEMENT (dvbbasebin), program->ghost);
|
||||
program->ghost = NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_dvb_base_bin_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (dvb_base_bin_debug, "dvbbasebin", 0, "DVB bin");
|
||||
|
||||
cam_init ();
|
||||
|
||||
return gst_element_register (plugin, "dvbbasebin",
|
||||
GST_RANK_NONE, GST_TYPE_DVB_BASE_BIN);
|
||||
}
|
75
sys/dvb/dvbbasebin.h
Normal file
75
sys/dvb/dvbbasebin.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* dvbbasebin.h -
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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_DVB_BASE_BIN_H
|
||||
#define GST_DVB_BASE_BIN_H
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <glib.h>
|
||||
#include "camdevice.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_DVB_BASE_BIN \
|
||||
(dvb_base_bin_get_type())
|
||||
#define GST_DVB_BASE_BIN(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVB_BASE_BIN,DvbBaseBin))
|
||||
#define GST_DVB_BASE_BIN_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVB_BASE_BIN,DvbBaseBinClass))
|
||||
#define GST_IS_DVB_BASE_BIN(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVB_BASE_BIN))
|
||||
#define GST_IS_DVB_BASE_BIN_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVB_BASE_BIN))
|
||||
|
||||
typedef struct _DvbBaseBin DvbBaseBin;
|
||||
typedef struct _DvbBaseBinClass DvbBaseBinClass;
|
||||
|
||||
struct _DvbBaseBin {
|
||||
GstBin bin;
|
||||
|
||||
GstPad *ts_pad;
|
||||
|
||||
GstElement *dvbsrc;
|
||||
GstElement *buffer_queue;
|
||||
GstElement *mpegtsparse;
|
||||
CamDevice *hwcam;
|
||||
GList *pmtlist;
|
||||
gboolean pmtlist_changed;
|
||||
gchar *filter;
|
||||
GHashTable *streams;
|
||||
GHashTable *programs;
|
||||
gboolean disposed;
|
||||
};
|
||||
|
||||
struct _DvbBaseBinClass {
|
||||
GstBinClass parent_class;
|
||||
|
||||
/* signals */
|
||||
};
|
||||
|
||||
GType gst_dvb_base_bin_get_type(void);
|
||||
gboolean gst_dvb_base_bin_plugin_init (GstPlugin *plugin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GST_DVB_BASE_BIN_H */
|
46
sys/dvb/gstdvb.c
Normal file
46
sys/dvb/gstdvb.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* gstdvb.c -
|
||||
* Copyright (C) 2007 Alessandro Decina
|
||||
*
|
||||
* Authors:
|
||||
* Alessandro Decina <alessandro@nnva.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstdvbsrc.h"
|
||||
#include "dvbbasebin.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
if (!gst_dvbsrc_plugin_init (plugin))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_dvb_base_bin_plugin_init (plugin))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"dvb",
|
||||
"DVB elements",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
|
@ -105,7 +105,8 @@ enum
|
|||
ARG_DVBSRC_TRANSMISSION_MODE,
|
||||
ARG_DVBSRC_HIERARCHY_INF,
|
||||
ARG_DVBSRC_TUNE,
|
||||
ARG_DVBSRC_INVERSION
|
||||
ARG_DVBSRC_INVERSION,
|
||||
ARG_DVBSRC_STATS_REPORTING_INTERVAL
|
||||
};
|
||||
|
||||
static void gst_dvbsrc_output_frontend_stats (GstDvbSrc * src);
|
||||
|
@ -246,9 +247,9 @@ gst_dvbsrc_inversion_get_type (void)
|
|||
{
|
||||
static GType dvbsrc_inversion_type = 0;
|
||||
static GEnumValue inversion_types[] = {
|
||||
{INVERSION_AUTO, "AUTO", "AUTO"},
|
||||
{INVERSION_OFF, "OFF", "OFF"},
|
||||
{INVERSION_ON, "ON", "ON"},
|
||||
{INVERSION_AUTO, "OFF", "OFF"},
|
||||
{INVERSION_AUTO, "AUTO", "AUTO"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
@ -384,50 +385,57 @@ gst_dvbsrc_class_init (GstDvbSrcClass * klass)
|
|||
g_object_class_install_property (gobject_class, ARG_DVBSRC_BANDWIDTH,
|
||||
g_param_spec_enum ("bandwidth",
|
||||
"bandwidth",
|
||||
"Bandwidth (DVB-T)", GST_TYPE_DVBSRC_BANDWIDTH, 1, G_PARAM_WRITABLE));
|
||||
"Bandwidth (DVB-T)", GST_TYPE_DVBSRC_BANDWIDTH, 1,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_DVBSRC_CODE_RATE_HP,
|
||||
g_param_spec_enum ("code-rate-hp",
|
||||
"code-rate-hp",
|
||||
"High Priority Code Rate (DVB-T)",
|
||||
GST_TYPE_DVBSRC_CODE_RATE, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_CODE_RATE, 1, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_DVBSRC_CODE_RATE_LP,
|
||||
g_param_spec_enum ("code-rate-lp",
|
||||
"code-rate-lp",
|
||||
"Low Priority Code Rate (DVB-T)",
|
||||
GST_TYPE_DVBSRC_CODE_RATE, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_CODE_RATE, 1, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_DVBSRC_GUARD,
|
||||
g_param_spec_enum ("guard",
|
||||
"guard",
|
||||
"Guard Interval (DVB-T)",
|
||||
GST_TYPE_DVBSRC_GUARD, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_GUARD, 1, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_DVBSRC_MODULATION,
|
||||
g_param_spec_enum ("modulation",
|
||||
"modulation",
|
||||
"Modulation (DVB-T)",
|
||||
GST_TYPE_DVBSRC_MODULATION, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_MODULATION, 1, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
ARG_DVBSRC_TRANSMISSION_MODE,
|
||||
g_param_spec_enum ("trans-mode",
|
||||
"trans-mode",
|
||||
"Transmission Mode (DVB-T)",
|
||||
GST_TYPE_DVBSRC_TRANSMISSION_MODE, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_TRANSMISSION_MODE, 1, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_DVBSRC_HIERARCHY_INF,
|
||||
g_param_spec_enum ("hierarchy",
|
||||
"hierarchy",
|
||||
"Hierarchy Information (DVB-T)",
|
||||
GST_TYPE_DVBSRC_HIERARCHY, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_HIERARCHY, 1, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_class, ARG_DVBSRC_INVERSION,
|
||||
g_param_spec_enum ("inversion",
|
||||
"inversion",
|
||||
"Inversion Information (DVB-T)",
|
||||
GST_TYPE_DVBSRC_INVERSION, 1, G_PARAM_WRITABLE));
|
||||
GST_TYPE_DVBSRC_INVERSION, 1, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
ARG_DVBSRC_STATS_REPORTING_INTERVAL,
|
||||
g_param_spec_uint ("stats-reporting-interval",
|
||||
"stats-reporting-interval",
|
||||
"The number of reads before reporting frontend stats",
|
||||
0, G_MAXUINT, 100, G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
/* initialize the new element
|
||||
|
@ -449,7 +457,7 @@ gst_dvbsrc_init (GstDvbSrc * object, GstDvbSrcClass * klass)
|
|||
object->fd_dvr = -1;
|
||||
|
||||
for (i = 0; i < MAX_FILTERS; i++) {
|
||||
object->pids[i] = 0;
|
||||
object->pids[i] = G_MAXUINT16;
|
||||
object->fd_filters[i] = -1;
|
||||
}
|
||||
/* Pid 8192 on DVB gets the whole transport stream */
|
||||
|
@ -504,32 +512,44 @@ gst_dvbsrc_set_property (GObject * _object, guint prop_id,
|
|||
break;
|
||||
case ARG_DVBSRC_PIDS:
|
||||
{
|
||||
int pid = 0;
|
||||
int pid_count = 0;
|
||||
gchar *pid_string;
|
||||
gchar **pids;
|
||||
char **tmp;
|
||||
|
||||
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_PIDS");
|
||||
pid_string = g_value_dup_string (value);
|
||||
tmp = pids = g_strsplit (pid_string, ":", MAX_FILTERS);
|
||||
while (*pids != NULL && pid_count < MAX_FILTERS) {
|
||||
pid = strtol (*pids, NULL, 0);
|
||||
if (pid > 0 && pid <= 8192) {
|
||||
GST_INFO_OBJECT (object, "Parsed Pid: %d\n", pid);
|
||||
object->pids[pid_count] = pid;
|
||||
pid_count++;
|
||||
if (!strcmp (pid_string, "8192")) {
|
||||
/* get the whole ts */
|
||||
object->pids[0] = 8192;
|
||||
} else {
|
||||
int pid = 0;
|
||||
int pid_count;
|
||||
gchar **pids;
|
||||
char **tmp;
|
||||
|
||||
tmp = pids = g_strsplit (pid_string, ":", MAX_FILTERS);
|
||||
|
||||
/* always add the PAT and CAT pids */
|
||||
object->pids[0] = 0;
|
||||
object->pids[1] = 1;
|
||||
|
||||
pid_count = 2;
|
||||
while (*pids != NULL && pid_count < MAX_FILTERS) {
|
||||
pid = strtol (*pids, NULL, 0);
|
||||
if (pid > 1 && pid <= 8192) {
|
||||
GST_INFO_OBJECT (object, "Parsed Pid: %d\n", pid);
|
||||
object->pids[pid_count] = pid;
|
||||
pid_count++;
|
||||
}
|
||||
pids++;
|
||||
}
|
||||
pids++;
|
||||
|
||||
g_strfreev (tmp);
|
||||
}
|
||||
g_strfreev (tmp);
|
||||
/* if we are in playing, then set filters now */
|
||||
GST_INFO_OBJECT (object, "checking if playing for setting pes filters");
|
||||
if (GST_ELEMENT (object)->current_state == GST_STATE_PLAYING) {
|
||||
GST_INFO_OBJECT (object, "Setting pes filters now");
|
||||
gst_dvbsrc_set_pes_filters (object);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case ARG_DVBSRC_SYM_RATE:
|
||||
|
@ -573,6 +593,10 @@ gst_dvbsrc_set_property (GObject * _object, guint prop_id,
|
|||
g_mutex_unlock (object->tune_mutex);
|
||||
}
|
||||
break;
|
||||
case ARG_DVBSRC_STATS_REPORTING_INTERVAL:
|
||||
object->stats_interval = g_value_get_uint (value);
|
||||
object->stats_counter = 0;
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
@ -610,6 +634,33 @@ gst_dvbsrc_get_property (GObject * _object, guint prop_id,
|
|||
case ARG_DVBSRC_DISEQC_SRC:
|
||||
g_value_set_int (value, object->diseqc_src);
|
||||
break;
|
||||
case ARG_DVBSRC_BANDWIDTH:
|
||||
g_value_set_enum (value, object->bandwidth);
|
||||
break;
|
||||
case ARG_DVBSRC_CODE_RATE_HP:
|
||||
g_value_set_enum (value, object->code_rate_hp);
|
||||
break;
|
||||
case ARG_DVBSRC_CODE_RATE_LP:
|
||||
g_value_set_enum (value, object->code_rate_lp);
|
||||
break;
|
||||
case ARG_DVBSRC_GUARD:
|
||||
g_value_set_enum (value, object->guard_interval);
|
||||
break;
|
||||
case ARG_DVBSRC_MODULATION:
|
||||
g_value_set_enum (value, object->modulation);
|
||||
break;
|
||||
case ARG_DVBSRC_TRANSMISSION_MODE:
|
||||
g_value_set_enum (value, object->transmission_mode);
|
||||
break;
|
||||
case ARG_DVBSRC_HIERARCHY_INF:
|
||||
g_value_set_enum (value, object->hierarchy_information);
|
||||
break;
|
||||
case ARG_DVBSRC_INVERSION:
|
||||
g_value_set_enum (value, object->inversion);
|
||||
break;
|
||||
case ARG_DVBSRC_STATS_REPORTING_INTERVAL:
|
||||
g_value_set_uint (value, object->stats_interval);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
@ -737,6 +788,9 @@ gst_dvbsrc_finalize (GObject * _object)
|
|||
|
||||
/* freeing the mutex segfaults somehow */
|
||||
g_mutex_free (object->tune_mutex);
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||
G_OBJECT_CLASS (parent_class)->finalize (_object);
|
||||
}
|
||||
|
||||
|
||||
|
@ -755,8 +809,8 @@ gst_dvbsrc_finalize (GObject * _object)
|
|||
* register the element factories and pad templates
|
||||
* register the features
|
||||
*/
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
gboolean
|
||||
gst_dvbsrc_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (gstdvbsrc_debug, "dvbsrc", 0, "DVB Source Element");
|
||||
|
||||
|
@ -770,12 +824,6 @@ plugin_init (GstPlugin * plugin)
|
|||
GST_TYPE_DVBSRC);
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"dvbsrc",
|
||||
"DVB Source", plugin_init, VERSION, "LGPL", "", "University of Paderborn");
|
||||
|
||||
|
||||
static GstBuffer *
|
||||
read_device (int fd, int adapter_number, int frontend_number, int size)
|
||||
{
|
||||
|
@ -843,7 +891,6 @@ read_device (int fd, int adapter_number, int frontend_number, int size)
|
|||
static GstFlowReturn
|
||||
gst_dvbsrc_create (GstPushSrc * element, GstBuffer ** buf)
|
||||
{
|
||||
static int quality_signal_rate = 0; /* FIXME: move into object struct? */
|
||||
gint buffer_size;
|
||||
GstFlowReturn retval = GST_FLOW_ERROR;
|
||||
GstDvbSrc *object;
|
||||
|
@ -871,17 +918,15 @@ gst_dvbsrc_create (GstPushSrc * element, GstBuffer ** buf)
|
|||
caps = gst_pad_get_caps (GST_BASE_SRC_PAD (object));
|
||||
gst_buffer_set_caps (*buf, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
/* Every now and then signal signal quality */
|
||||
if (quality_signal_rate == 100) {
|
||||
gst_dvbsrc_output_frontend_stats (object);
|
||||
quality_signal_rate = 0;
|
||||
} else {
|
||||
quality_signal_rate++;
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (object, "Failed to read from device");
|
||||
}
|
||||
|
||||
if (object->stats_interval != 0 &&
|
||||
++object->stats_counter == object->stats_interval) {
|
||||
gst_dvbsrc_output_frontend_stats (object);
|
||||
object->stats_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (object->tune_mutex);
|
||||
|
@ -1188,7 +1233,7 @@ gst_dvbsrc_set_pes_filters (GstDvbSrc * object)
|
|||
GST_INFO_OBJECT (object, "Setting PES filter");
|
||||
|
||||
for (i = 0; i < MAX_FILTERS; i++) {
|
||||
if (object->pids[i] == 0)
|
||||
if (object->pids[i] == G_MAXUINT16)
|
||||
break;
|
||||
|
||||
fd = &object->fd_filters[i];
|
||||
|
@ -1214,29 +1259,6 @@ gst_dvbsrc_set_pes_filters (GstDvbSrc * object)
|
|||
GST_WARNING_OBJECT (object, "Error setting PES filter on %s: %s",
|
||||
demux_dev, strerror (errno));
|
||||
}
|
||||
/* always have PAT in the filter if we haven't used all our filter slots */
|
||||
if (object->pids[0] != 8192 && i < MAX_FILTERS) {
|
||||
/* pid 8192 means get whole ts */
|
||||
pes_filter.pid = 0;
|
||||
pes_filter.input = DMX_IN_FRONTEND;
|
||||
pes_filter.output = DMX_OUT_TS_TAP;
|
||||
pes_filter.pes_type = DMX_PES_OTHER;
|
||||
pes_filter.flags = DMX_IMMEDIATE_START;
|
||||
|
||||
fd = &object->fd_filters[i];
|
||||
close (*fd);
|
||||
if ((*fd = open (demux_dev, O_RDWR)) < 0) {
|
||||
GST_WARNING_OBJECT ("Error opening demuxer: %s (%s)",
|
||||
strerror (errno), demux_dev);
|
||||
} else {
|
||||
GST_INFO_OBJECT (object, "Setting pes-filter, pid = %d, type = %d",
|
||||
pes_filter.pid, pes_filter.pes_type);
|
||||
|
||||
if (ioctl (*fd, DMX_SET_PES_FILTER, &pes_filter) < 0)
|
||||
GST_WARNING_OBJECT (object, "Error setting PES filter on %s: %s",
|
||||
demux_dev, strerror (errno));
|
||||
}
|
||||
}
|
||||
g_free (demux_dev);
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ G_BEGIN_DECLS
|
|||
#define DEFAULT_BUFFER_SIZE 8192
|
||||
#define DEFAULT_DISEQC_SRC -1 /* disabled */
|
||||
|
||||
#define MAX_FILTERS 8
|
||||
#define MAX_FILTERS 32
|
||||
|
||||
/* #define's don't like whitespacey bits */
|
||||
#define GST_TYPE_DVBSRC \
|
||||
|
@ -76,6 +76,8 @@ G_BEGIN_DECLS
|
|||
int inversion;
|
||||
|
||||
GstDvbSrcPol pol;
|
||||
guint stats_interval;
|
||||
guint stats_counter;
|
||||
};
|
||||
|
||||
struct _GstDvbSrcClass
|
||||
|
@ -88,6 +90,7 @@ G_BEGIN_DECLS
|
|||
|
||||
|
||||
GType gst_dvbsrc_get_type (void);
|
||||
gboolean gst_dvbsrc_plugin_init (GstPlugin *plugin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
Loading…
Reference in a new issue