tvheadend/src/input/mpegts.h

862 lines
25 KiB
C

/*
* Tvheadend - TS file input system
*
* Copyright (C) 2013 Adam Sutton
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TVH_MPEGTS_H__
#define __TVH_MPEGTS_H__
#ifndef __TVH_INPUT_H__
#error "Use header file input.h not input/mpegts.h"
#endif
#include "input.h"
#include "service.h"
#include "mpegts/dvb.h"
#include "subscriptions.h"
#define MPEGTS_ONID_NONE 0xFFFF
#define MPEGTS_TSID_NONE 0xFFFF
#define MPEGTS_PSI_SECTION_SIZE 5000
#define MPEGTS_FULLMUX_PID 0x2000
#define MPEGTS_PID_NONE 0xFFFF
/* Types */
typedef struct mpegts_table mpegts_table_t;
typedef struct mpegts_psi_section mpegts_psi_section_t;
typedef struct mpegts_network mpegts_network_t;
typedef struct mpegts_mux mpegts_mux_t;
typedef struct mpegts_service mpegts_service_t;
typedef struct mpegts_mux_instance mpegts_mux_instance_t;
typedef struct mpegts_mux_sub mpegts_mux_sub_t;
typedef struct mpegts_input mpegts_input_t;
typedef struct mpegts_table_feed mpegts_table_feed_t;
typedef struct mpegts_network_link mpegts_network_link_t;
typedef struct mpegts_packet mpegts_packet_t;
typedef struct mpegts_buffer mpegts_buffer_t;
/* Lists */
typedef LIST_HEAD (,mpegts_network) mpegts_network_list_t;
typedef LIST_HEAD (,mpegts_input) mpegts_input_list_t;
typedef TAILQ_HEAD(mpegts_mux_queue,mpegts_mux) mpegts_mux_queue_t;
typedef LIST_HEAD (,mpegts_mux) mpegts_mux_list_t;
typedef LIST_HEAD (,mpegts_network_link) mpegts_network_link_list_t;
typedef TAILQ_HEAD(mpegts_table_feed_queue, mpegts_table_feed)
mpegts_table_feed_queue_t;
/* Classes */
extern const idclass_t mpegts_network_class;
extern const idclass_t mpegts_mux_class;
extern const idclass_t mpegts_service_class;
extern const idclass_t mpegts_input_class;
/* **************************************************************************
* Setup / Tear down
* *************************************************************************/
void mpegts_init ( int linuxdvb_mask, str_list_t *satip_client,
str_list_t *tsfiles, int tstuners );
void mpegts_done ( void );
/* **************************************************************************
* Data / SI processing
* *************************************************************************/
struct mpegts_packet
{
TAILQ_ENTRY(mpegts_packet) mp_link;
size_t mp_len;
mpegts_mux_t *mp_mux;
uint8_t mp_data[0];
};
typedef int (*mpegts_table_callback_t)
( mpegts_table_t*, const uint8_t *buf, int len, int tableid );
typedef void (*mpegts_psi_section_callback_t)
( const uint8_t *tsb, size_t len, void *opaque );
struct mpegts_table_mux_cb
{
int tag;
int (*cb) ( mpegts_table_t*, mpegts_mux_t *mm,
const uint8_t dtag, const uint8_t *dptr, int dlen );
};
struct mpegts_psi_section
{
int ps_offset;
int ps_lock;
uint8_t ps_data[MPEGTS_PSI_SECTION_SIZE];
};
typedef struct mpegts_table_state
{
int tableid;
uint64_t extraid;
int version;
int complete;
uint32_t sections[8];
RB_ENTRY(mpegts_table_state) link;
} mpegts_table_state_t;
typedef struct mpegts_pid_sub
{
RB_ENTRY(mpegts_pid_sub) mps_link;
#define MPS_NONE 0x0
#define MPS_STREAM 0x1
#define MPS_TABLE 0x2
#define MPS_FTABLE 0x4
int mps_type;
void *mps_owner;
} mpegts_pid_sub_t;
typedef struct mpegts_pid
{
int mp_pid;
int mp_fd; // linuxdvb demux fd
int8_t mp_cc;
RB_HEAD(,mpegts_pid_sub) mp_subs; // subscribers to pid
RB_ENTRY(mpegts_pid) mp_link;
} mpegts_pid_t;
struct mpegts_table
{
/**
* Flags, must never be changed after creation.
* We inspect it without holding global_lock
*/
int mt_flags;
#define MT_CRC 0x0001
#define MT_FULL 0x0002
#define MT_QUICKREQ 0x0004
#define MT_RECORD 0x0008
#define MT_SKIPSUBS 0x0010
#define MT_SCANSUBS 0x0020
#define MT_FAST 0x0040
#define MT_SLOW 0x0080
#define MT_DEFER 0x0100
/**
* Cycle queue
* Tables that did not get a fd or filter in hardware will end up here
* waiting for any other table to be received so it can reuse that fd.
* Only linked if fd == -1
*/
TAILQ_ENTRY(mpegts_table) mt_pending_link;
/**
* File descriptor for filter
*/
LIST_ENTRY(mpegts_table) mt_link;
TAILQ_ENTRY(mpegts_table) mt_defer_link;
mpegts_mux_t *mt_mux;
char *mt_name;
void *mt_opaque;
mpegts_table_callback_t mt_callback;
RB_HEAD(,mpegts_table_state) mt_state;
int mt_complete;
int mt_incomplete;
uint8_t mt_finished;
uint8_t mt_subscribed;
uint8_t mt_defer_cmd;
#define MT_DEFER_OPEN_PID 1
#define MT_DEFER_CLOSE_PID 2
int mt_count;
int mt_pid;
int mt_id;
int mt_table; // SI table id (base)
int mt_mask; // mask
int mt_destroyed; // Refcounting
int mt_refcount;
int8_t mt_cc;
tvhlog_limit_t mt_err_log;
mpegts_psi_section_t mt_sect;
struct mpegts_table_mux_cb *mt_mux_cb;
mpegts_service_t *mt_service;
void (*mt_destroy) (mpegts_table_t *mt); // Allow customisable destroy hook
// useful for dynamic allocation of
// the opaque field
};
/**
* When in raw mode we need to enqueue raw TS packet
* to a different thread because we need to hold
* global_lock when doing delivery of the tables
*/
struct mpegts_table_feed {
TAILQ_ENTRY(mpegts_table_feed) mtf_link;
uint8_t mtf_tsb[188];
mpegts_mux_t *mtf_mux;
};
/*
* Assemble SI section
*/
void mpegts_psi_section_reassemble
( mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
mpegts_psi_section_callback_t cb, void *opaque );
/* **************************************************************************
* Logical network
* *************************************************************************/
/* Network/Input linkage */
struct mpegts_network_link
{
int mnl_mark;
mpegts_input_t *mnl_input;
mpegts_network_t *mnl_network;
LIST_ENTRY(mpegts_network_link) mnl_mn_link;
LIST_ENTRY(mpegts_network_link) mnl_mi_link;
};
/* Network */
struct mpegts_network
{
idnode_t mn_id;
LIST_ENTRY(mpegts_network) mn_global_link;
/*
* Identification
*/
char *mn_network_name;
/*
* Inputs
*/
mpegts_network_link_list_t mn_inputs;
/*
* Multiplexes
*/
mpegts_mux_list_t mn_muxes;
/*
* Scanning
*/
mpegts_mux_queue_t mn_scan_pend; // Pending muxes
mpegts_mux_queue_t mn_scan_active; // Active muxes
gtimer_t mn_scan_timer; // Timer for activity
/*
* Functions
*/
void (*mn_display_name) (mpegts_network_t*, char *buf, size_t len);
void (*mn_config_save) (mpegts_network_t*);
mpegts_mux_t* (*mn_create_mux)
(mpegts_mux_t*, uint16_t onid, uint16_t tsid, void *conf);
mpegts_service_t* (*mn_create_service)
(mpegts_mux_t*, uint16_t sid, uint16_t pmt_pid);
const idclass_t* (*mn_mux_class) (mpegts_network_t*);
mpegts_mux_t * (*mn_mux_create2) (mpegts_network_t *mn, htsmsg_t *conf);
/*
* Configuration
*/
uint16_t mn_nid;
int mn_autodiscovery;
int mn_skipinitscan;
char *mn_charset;
int mn_idlescan;
int mn_ignore_chnum;
};
typedef enum mpegts_mux_scan_state
{
MM_SCAN_STATE_IDLE, // Nothing
MM_SCAN_STATE_PEND, // Queue'd pending scan
MM_SCAN_STATE_ACTIVE, // Scan is active
} mpegts_mux_scan_state_t;
typedef enum mpegts_mux_scan_result
{
MM_SCAN_NONE,
MM_SCAN_OK,
MM_SCAN_FAIL
} mpegts_mux_scan_result_t;
enum mpegts_mux_epg_flag
{
MM_EPG_DISABLE,
MM_EPG_ENABLE,
MM_EPG_FORCE,
MM_EPG_ONLY_EIT,
MM_EPG_ONLY_UK_FREESAT,
MM_EPG_ONLY_UK_FREEVIEW,
MM_EPG_ONLY_VIASAT_BALTIC,
MM_EPG_ONLY_OPENTV_SKY_UK,
MM_EPG_ONLY_OPENTV_SKY_ITALIA,
MM_EPG_ONLY_OPENTV_SKY_AUSAT,
};
#define MM_EPG_LAST MM_EPG_ONLY_OPENTV_SKY_AUSAT
/* Multiplex */
struct mpegts_mux
{
idnode_t mm_id;
/*
* Identification
*/
LIST_ENTRY(mpegts_mux) mm_network_link;
mpegts_network_t *mm_network;
uint16_t mm_onid;
uint16_t mm_tsid;
/*
* Services
*/
LIST_HEAD(,mpegts_service) mm_services;
/*
* Scanning
*/
mpegts_mux_scan_result_t mm_scan_result; ///< Result of last scan
int mm_scan_weight; ///< Scan priority
int mm_scan_init; ///< Flag to timeout handler
gtimer_t mm_scan_timeout; ///< Timer to handle timeout
TAILQ_ENTRY(mpegts_mux) mm_scan_link; ///< Link to Queue
mpegts_mux_scan_state_t mm_scan_state; ///< Scanning state
#if 0
enum {
MM_ORIG_USER, ///< Manually added
MM_ORIG_FILE, ///< Added from scan file
MM_ORIG_AUTO ///< From NIT
} mm_dmc_origin2;
#endif
mpegts_mux_t *mm_dmc_origin;
time_t mm_dmc_origin_expire;
/*
* Physical instances
*/
LIST_HEAD(, mpegts_mux_instance) mm_instances;
mpegts_mux_instance_t *mm_active;
/*
* Data processing
*/
RB_HEAD(, mpegts_pid) mm_pids;
int mm_last_pid;
mpegts_pid_t *mm_last_mp;
int mm_num_tables;
LIST_HEAD(, mpegts_table) mm_tables;
TAILQ_HEAD(, mpegts_table) mm_defer_tables;
pthread_mutex_t mm_tables_lock;
TAILQ_HEAD(, mpegts_table) mm_table_queue;
LIST_HEAD(, caid) mm_descrambler_caids;
TAILQ_HEAD(, descrambler_table) mm_descrambler_tables;
TAILQ_HEAD(, descrambler_emm) mm_descrambler_emms;
pthread_mutex_t mm_descrambler_lock;
int mm_descrambler_flush;
/*
* Functions
*/
void (*mm_delete) (mpegts_mux_t *mm, int delconf);
void (*mm_config_save) (mpegts_mux_t *mm);
void (*mm_display_name) (mpegts_mux_t*, char *buf, size_t len);
int (*mm_is_enabled) (mpegts_mux_t *mm);
int (*mm_start) (mpegts_mux_t *mm, const char *r, int w, int flags);
void (*mm_stop) (mpegts_mux_t *mm, int force);
void (*mm_open_table) (mpegts_mux_t*,mpegts_table_t*,int subscribe);
void (*mm_close_table) (mpegts_mux_t*,mpegts_table_t*);
void (*mm_create_instances) (mpegts_mux_t*);
int (*mm_is_epg) (mpegts_mux_t*);
/*
* Configuration
*/
char *mm_crid_authority;
int mm_enabled;
int mm_epg;
char *mm_charset;
int mm_pmt_06_ac3;
};
/* Service */
struct mpegts_service
{
service_t; // Parent
/*
* Fields defined by DVB standard EN 300 468
*/
uint16_t s_dvb_service_id;
uint16_t s_dvb_channel_num;
uint16_t s_dvb_channel_minor;
char *s_dvb_svcname;
char *s_dvb_provider;
char *s_dvb_cridauth;
uint16_t s_dvb_servicetype;
char *s_dvb_charset;
uint16_t s_dvb_prefcapid;
int s_dvb_prefcapid_lock;
uint16_t s_dvb_forcecaid;
/*
* EIT/EPG control
*/
int s_dvb_eit_enable;
uint64_t s_dvb_opentv_chnum;
/*
* Link to carrying multiplex and active adapter
*/
LIST_ENTRY(mpegts_service) s_dvb_mux_link;
mpegts_mux_t *s_dvb_mux;
mpegts_input_t *s_dvb_active_input;
/*
* Streaming elements
*
* see service.h for locking rules
*/
/**
* When a subscription request SMT_MPEGTS, chunk them togeather
* in order to recude load.
*/
sbuf_t s_tsbuf;
/**
* Average continuity errors
*/
avgstat_t s_cc_errors;
/**
* PCR drift compensation. This should really be per-packet.
*/
int64_t s_pcr_drift;
/**
* PMT monitoring
*/
mpegts_table_t *s_pmt_mon; ///< Table entry for monitoring PMT
};
/* **************************************************************************
* Physical Network
* *************************************************************************/
/* Physical mux instance */
struct mpegts_mux_instance
{
idnode_t mmi_id;
LIST_ENTRY(mpegts_mux_instance) mmi_mux_link;
LIST_ENTRY(mpegts_mux_instance) mmi_input_link;
LIST_ENTRY(mpegts_mux_instance) mmi_active_link;
streaming_pad_t mmi_streaming_pad;
mpegts_mux_t *mmi_mux;
mpegts_input_t *mmi_input;
LIST_HEAD(,th_subscription) mmi_subs;
tvh_input_stream_stats_t mmi_stats;
int mmi_tune_failed;
void (*mmi_delete) (mpegts_mux_instance_t *mmi);
};
struct mpegts_mux_sub
{
RB_ENTRY(mpegts_mux_sub) mms_link;
void *mms_src;
int mms_weight;
};
/* Input source */
struct mpegts_input
{
tvh_input_t;
int mi_enabled;
int mi_instance;
char *mi_name;
int mi_priority;
int mi_streaming_priority;
int mi_ota_epg;
LIST_ENTRY(mpegts_input) mi_global_link;
mpegts_network_link_list_t mi_networks;
LIST_HEAD(,mpegts_mux_instance) mi_mux_instances;
/*
* Status
*/
gtimer_t mi_status_timer;
/*
* Input processing
*/
uint8_t mi_running; /* threads running */
uint8_t mi_stop; /* mux is in the stop state */
uint8_t mi_live; /* stream is live */
time_t mi_last_dispatch;
/* Data input */
// Note: this section is protected by mi_input_lock
pthread_t mi_input_tid;
pthread_mutex_t mi_input_lock;
pthread_cond_t mi_input_cond;
TAILQ_HEAD(,mpegts_packet) mi_input_queue;
/* Data processing/output */
// Note: this lock (mi_output_lock) protects all the remaining
// data fields (excluding the callback functions)
pthread_mutex_t mi_output_lock;
/* Active sources */
LIST_HEAD(,mpegts_mux_instance) mi_mux_active;
LIST_HEAD(,service) mi_transports;
/* Table processing */
pthread_t mi_table_tid;
pthread_cond_t mi_table_cond;
mpegts_table_feed_queue_t mi_table_queue;
/* DBus */
#if ENABLE_DBUS_1
int64_t mi_dbus_subs;
#endif
/*
* Functions
*/
int (*mi_is_enabled) (mpegts_input_t*, mpegts_mux_t *mm, const char *reason);
void (*mi_enabled_updated)(mpegts_input_t*);
void (*mi_display_name) (mpegts_input_t*, char *buf, size_t len);
int (*mi_is_free) (mpegts_input_t*);
int (*mi_get_weight) (mpegts_input_t*, int flags);
int (*mi_get_priority) (mpegts_input_t*, mpegts_mux_t *mm, int flags);
int (*mi_get_grace) (mpegts_input_t*, mpegts_mux_t *mm);
int (*mi_warm_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
int (*mi_start_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
void (*mi_stop_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
void (*mi_open_service) (mpegts_input_t*,mpegts_service_t*,int first);
void (*mi_close_service) (mpegts_input_t*,mpegts_service_t*);
mpegts_pid_t *(*mi_open_pid)(mpegts_input_t*,mpegts_mux_t*,int,int,void*);
void (*mi_close_pid) (mpegts_input_t*,mpegts_mux_t*,int,int,void*);
void (*mi_create_mux_instance) (mpegts_input_t*,mpegts_mux_t*);
void (*mi_started_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
void (*mi_stopping_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
void (*mi_stopped_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
int (*mi_has_subscription) (mpegts_input_t*, mpegts_mux_t *mm);
idnode_set_t *(*mi_network_list) (mpegts_input_t*);
};
/* ****************************************************************************
* Lists
* ***************************************************************************/
extern mpegts_network_list_t mpegts_network_all;
typedef struct mpegts_network_builder {
LIST_ENTRY(mpegts_network_builder) link;
const idclass_t *idc;
mpegts_network_t * (*build) ( const idclass_t *idc, htsmsg_t *conf );
} mpegts_network_builder_t;
typedef LIST_HEAD(,mpegts_network_builder) mpegts_network_builder_list_t;
extern mpegts_network_builder_list_t mpegts_network_builders;
extern mpegts_input_list_t mpegts_input_all;
/* ****************************************************************************
* Functions
* ***************************************************************************/
mpegts_input_t *mpegts_input_create0
( mpegts_input_t *mi, const idclass_t *idc, const char *uuid, htsmsg_t *c );
#define mpegts_input_create(t, u, c)\
(struct t*)mpegts_input_create0(calloc(1, sizeof(struct t)), &t##_class, u, c)
#define mpegts_input_create1(u, c)\
mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\
&mpegts_input_class, u, c)
void mpegts_input_stop_all ( mpegts_input_t *mi );
void mpegts_input_delete ( mpegts_input_t *mi, int delconf );
static inline mpegts_input_t *mpegts_input_find(const char *uuid)
{ return idnode_find(uuid, &mpegts_input_class, NULL); }
int mpegts_input_set_networks ( mpegts_input_t *mi, htsmsg_t *msg );
int mpegts_input_add_network ( mpegts_input_t *mi, mpegts_network_t *mn );
void mpegts_input_open_service ( mpegts_input_t *mi, mpegts_service_t *s, int init );
void mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s );
void mpegts_input_status_timer ( void *p );
int mpegts_input_grace ( mpegts_input_t * mi, mpegts_mux_t * mm );
int mpegts_input_is_enabled ( mpegts_input_t * mi, mpegts_mux_t *mm, const char *reason );
/* TODO: exposing these class methods here is a bit of a hack */
const void *mpegts_input_class_network_get ( void *o );
int mpegts_input_class_network_set ( void *o, const void *p );
htsmsg_t *mpegts_input_class_network_enum ( void *o );
char *mpegts_input_class_network_rend ( void *o );
void mpegts_network_register_builder
( const idclass_t *idc,
mpegts_network_t *(*build)(const idclass_t *idc, htsmsg_t *conf) );
void mpegts_network_unregister_builder
( const idclass_t *idc );
mpegts_network_t *mpegts_network_build
( const char *clazz, htsmsg_t *conf );
mpegts_network_t *mpegts_network_create0
( mpegts_network_t *mn, const idclass_t *idc, const char *uuid,
const char *name, htsmsg_t *conf );
#define mpegts_network_create(t, u, n, c)\
(struct t*)mpegts_network_create0(calloc(1, sizeof(struct t)), &t##_class, u, n, c)
extern const idclass_t mpegts_network_class;
static inline mpegts_network_t *mpegts_network_find(const char *uuid)
{ return idnode_find(uuid, &mpegts_network_class, NULL); }
mpegts_mux_t *mpegts_network_find_mux
(mpegts_network_t *mn, uint16_t onid, uint16_t tsid);
void mpegts_network_class_delete ( const idclass_t *idc, int delconf );
void mpegts_network_delete ( mpegts_network_t *mn, int delconf );
int mpegts_network_set_nid ( mpegts_network_t *mn, uint16_t nid );
int mpegts_network_set_network_name ( mpegts_network_t *mn, const char *name );
mpegts_mux_t *mpegts_mux_create0
( mpegts_mux_t *mm, const idclass_t *class, const char *uuid,
mpegts_network_t *mn, uint16_t onid, uint16_t tsid,
htsmsg_t *conf );
#define mpegts_mux_create(type, uuid, mn, onid, tsid, conf)\
(struct type*)mpegts_mux_create0(calloc(1, sizeof(struct type)),\
&type##_class, uuid,\
mn, onid, tsid, conf)
#define mpegts_mux_create1(uuid, mn, onid, tsid, conf)\
mpegts_mux_create0(calloc(1, sizeof(mpegts_mux_t)), &mpegts_mux_class, uuid,\
mn, onid, tsid, conf)
static inline mpegts_mux_t *mpegts_mux_find(const char *uuid)
{ return idnode_find(uuid, &mpegts_mux_class, NULL); }
#define mpegts_mux_delete_by_uuid(u, delconf)\
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm, delconf); }
void mpegts_mux_delete ( mpegts_mux_t *mm, int delconf );
void mpegts_mux_save ( mpegts_mux_t *mm, htsmsg_t *c );
mpegts_mux_instance_t *mpegts_mux_instance_create0
( mpegts_mux_instance_t *mmi, const idclass_t *class, const char *uuid,
mpegts_input_t *mi, mpegts_mux_t *mm );
mpegts_service_t *mpegts_mux_find_service(mpegts_mux_t *ms, uint16_t sid);
#define mpegts_mux_instance_create(type, uuid, mi, mm)\
(struct type*)mpegts_mux_instance_create0(calloc(1, sizeof(struct type)),\
&type##_class, uuid,\
mi, mm);
int mpegts_mux_instance_start
( mpegts_mux_instance_t **mmiptr );
int mpegts_mux_instance_weight ( mpegts_mux_instance_t *mmi );
int mpegts_mux_set_tsid ( mpegts_mux_t *mm, uint16_t tsid, int force );
int mpegts_mux_set_onid ( mpegts_mux_t *mm, uint16_t onid );
int mpegts_mux_set_crid_authority ( mpegts_mux_t *mm, const char *defauth );
void mpegts_mux_open_table ( mpegts_mux_t *mm, mpegts_table_t *mt, int subscribe );
void mpegts_mux_close_table ( mpegts_mux_t *mm, mpegts_table_t *mt );
void mpegts_mux_remove_subscriber(mpegts_mux_t *mm, th_subscription_t *s, int reason);
int mpegts_mux_subscribe(mpegts_mux_t *mm, const char *name, int weight);
void mpegts_mux_unsubscribe_by_name(mpegts_mux_t *mm, const char *name);
void mpegts_mux_scan_done ( mpegts_mux_t *mm, const char *buf, int res );
void mpegts_mux_nice_name( mpegts_mux_t *mm, char *buf, size_t len );
mpegts_pid_t *mpegts_mux_find_pid_(mpegts_mux_t *mm, int pid, int create);
static inline mpegts_pid_t *
mpegts_mux_find_pid(mpegts_mux_t *mm, int pid, int create)
{
if (mm->mm_last_pid != pid)
return mpegts_mux_find_pid_(mm, pid, create);
else
return mm->mm_last_mp;
}
void mpegts_input_recv_packets
(mpegts_input_t *mi, mpegts_mux_instance_t *mmi, sbuf_t *sb,
int64_t *pcr, uint16_t *pcr_pid);
int mpegts_input_is_free ( mpegts_input_t *mi );
int mpegts_input_get_weight ( mpegts_input_t *mi, int flags );
int mpegts_input_get_priority ( mpegts_input_t *mi, mpegts_mux_t *mm, int flags );
int mpegts_input_get_grace ( mpegts_input_t *mi, mpegts_mux_t *mm );
void mpegts_input_save ( mpegts_input_t *mi, htsmsg_t *c );
void mpegts_input_flush_mux ( mpegts_input_t *mi, mpegts_mux_t *mm );
mpegts_pid_t * mpegts_input_open_pid
( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner );
void mpegts_input_close_pid
( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner );
void mpegts_table_dispatch
(const uint8_t *sec, size_t r, void *mt);
static inline void mpegts_table_grab
(mpegts_table_t *mt) { mt->mt_refcount++; }
void mpegts_table_release_
(mpegts_table_t *mt);
static inline void mpegts_table_release
(mpegts_table_t *mt)
{
assert(mt->mt_refcount > 0);
if(--mt->mt_refcount == 0) mpegts_table_release_(mt);
}
int mpegts_table_type
( mpegts_table_t *mt );
mpegts_table_t *mpegts_table_add
(mpegts_mux_t *mm, int tableid, int mask,
mpegts_table_callback_t callback, void *opaque,
const char *name, int flags, int pid);
void mpegts_table_flush_all
(mpegts_mux_t *mm);
void mpegts_table_destroy ( mpegts_table_t *mt );
void mpegts_table_consistency_check( mpegts_mux_t *mm );
mpegts_service_t *mpegts_service_create0
( mpegts_service_t *ms, const idclass_t *class, const char *uuid,
mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, htsmsg_t *conf );
#define mpegts_service_create(t, u, m, s, p, c)\
(struct t*)mpegts_service_create0(calloc(1, sizeof(struct t)),\
&t##_class, u, m, s, p, c)
#define mpegts_service_create1(u, m, s, p, c)\
mpegts_service_create0(calloc(1, sizeof(mpegts_service_t)),\
&mpegts_service_class, u, m, s, p, c)
mpegts_service_t *mpegts_service_find
( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, int create, int *save );
static inline mpegts_service_t *mpegts_service_find_by_uuid(const char *uuid)
{ return idnode_find(uuid, &mpegts_service_class, NULL); }
void mpegts_service_delete ( service_t *s, int delconf );
/*
* MPEG-TS event handler
*/
typedef struct mpegts_listener
{
LIST_ENTRY(mpegts_listener) ml_link;
void *ml_opaque;
void (*ml_mux_start) (mpegts_mux_t *mm, void *p);
void (*ml_mux_stop) (mpegts_mux_t *mm, void *p);
void (*ml_mux_create) (mpegts_mux_t *mm, void *p);
void (*ml_mux_delete) (mpegts_mux_t *mm, void *p);
} mpegts_listener_t;
LIST_HEAD(,mpegts_listener) mpegts_listeners;
#define mpegts_add_listener(ml)\
LIST_INSERT_HEAD(&mpegts_listeners, ml, ml_link)
#define mpegts_rem_listener(ml)\
LIST_REMOVE(ml, ml_link)
#define mpegts_fire_event(t, op)\
{\
mpegts_listener_t *ml;\
LIST_FOREACH(ml, &mpegts_listeners, ml_link)\
if (ml->op) ml->op(t, ml->ml_opaque);\
} (void)0
#endif /* __TVH_MPEGTS_H__ */
/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/