Commit bcac7691 authored by massiot's avatar massiot

* dvblast: Initial import of DVBlast 1.0.


git-svn-id: svn://svn.videolan.org/dvblast/trunk@1 55d3f8b6-4a41-4d2d-a900-313d1436a5b8
parents
DVBlast is mostly written by Christophe Massiot <massiot@via.ecp.fr>. Parts of the code may be
borrowed from VLC, from various contributors.
This diff is collapsed.
dvblast-1.0:
- First public release
Installing DVBlast
==================
No autotools yet... You have to tweak the Makefile by hand, especially
if your kernel is S2API-enabled but not your distribution (indicate the
path of your kernel where appropriate). Compile the program with `make`.
Tuning DVBlast
==============
You usually want to supply DVBlast with the parameters of a transponder,
for instance for DVB-S :
dvblast -f 11570000 -s 27500000 -v 18
This tunes to frequency 11570 MHz, symbol rate 27500, horizontal (-v 18). For
DVB-S2, you must indicate a modulation with -m qpsk or -m psk_8. For DVB-T,
a bandwidth (usually -b 8 for 8 MHz multiplexes).
Configuring outputs
===================
DVBlast reads a configuration file containing one or several lines in the
format :
<IP>[:<port>] <always on> <SID> [<PID>,]*
For instance :
239.255.0.1:1234 1 10750 1234,1235,1236
The configuration file can be reloaded by sending "HUP" to the program, or
via the dvblastctl program.
The "always on" flag tells DVBlast whether the channel is expected to
be on at all times or if it may break. If set to "1", then DVBlast will
regularly reset the CAM module if it fails to descramble the service,
assuming the module is dead. Every time it is reset a few TS packets
will be lost, that is why this feature is optional.
There are three ways of configuring the PIDs to stream :
1. SID-based
239.255.0.1:1234 1 10750
DVBlast will stream all known PIDs from service 10750 (video, audio, and
subtitles). The resulting stream is fully MPEG-compliant, with PAT and PMT.
2. SID and PIDs
239.255.0.1:1234 1 10750 1234,1235
DVBlast will stream SID 10750, but only PID 1234 and 1235 will be output.
Other known PIDs will be discarded and removed from the PMT. The list of
PIDs in the config file does not include the PAT and PMT, but it must
include the PCR PID if it is different from the video or audio PID, otherwise
the stream won't be compliant.
3. PIDs only
239.255.0.1:1234 1 0 0,128,1234,1235
DVBlast will only stream the PIDs passed. No PAT and PMT will be generated,
so if they are not included the stream won't be compliant. Also the
included PAT and PMT may contain ghost programs or ESes.
Note that the CAM will not be programmed in that case (unless it has
been programmed by another line of the config file). The file is read
from the command-line :
dvblast -c /tmp/dvblast.conf
Monitoring
==========
If dvblast is run with the -r option, the dvblastctl program can be used
to retrieve information from DVBlast about the front-end or CAM module.
dvblastctl -r /tmp/dvblast.sock fe_status
dvblastctl -r /tmp/dvblast.sock mmi_status
dvblastctl -r /tmp/dvblast.sock shutdown
CAM menu
========
For easier access to the CAM menus, the dvblast_mmi.sh shell script is
provided :
dvblast_mmi.sh -r /tmp/dvblast.sock
Advanced features
=================
DVBlast may handle several DVB adapters in the same machine with the -a switch.
For better latency, run DVBlast in real-time priority (-i 1).
DVBlast can also stream the entire transponder to an address :
dvblast -u -d 172.16.42.42:1235 -f 11570000 -s 27500000 -v 18
The -u switch disables the PID filters, so that all PIDs, even the
unused ones, can be output.
# DVBlast Makefile
# Customise the path of your kernel
CFLAGS += -Wall -O3 -fomit-frame-pointer
CFLAGS += -g
CFLAGS += -I/usr/src/kernel/linux-2.6.29.1/include
LDFLAGS_DVBLAST += -ldvbpsi -lpthread
OBJ_DVBLAST = dvblast.o util.o dvb.o demux.o output.o en50221.o comm.o
OBJ_DVBLASTCTL = util.o dvblastctl.o
all: dvblast dvblastctl
$(OBJ_DVBLAST) $(OBJ_DVBLASTCTL): Makefile dvblast.h en50221.h comm.h
dvblast: $(OBJ_DVBLAST)
$(CC) -o $@ $(OBJ_DVBLAST) $(LDFLAGS_DVBLAST)
dvblastctl: $(OBJ_DVBLASTCTL)
clean:
-rm -f dvblast dvblastctl $(OBJ_DVBLAST) $(OBJ_DVBLASTCTL)
Welcome to DVBlast !
DVBlast is a simple and powerful streaming application based on the
linux-dvb API. It opens a DVB device, tunes it, places PID filters,
configures a CAM module, and demultiplexes the packets to several RTP
outputs. The configuration file for RTP outputs can be reloaded without
losing a single packet. All of this with a minimal memory and CPU
footprint. It has very few dependancies (libdvbpsi and libc). It also
supports the new S2API of linux-dvb.
--
Meuuh 2009-05-05
- Test and enhance the API for DVB-C, H, and ATSC support
- Win32 support
- Improve build system (autostuff)
- Parse the IOD to get a more precise idea of useful PIDs
/*****************************************************************************
* comm.c
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id: dvblast.c 11 2007-08-09 18:54:37Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <errno.h>
#include "dvblast.h"
#include "en50221.h"
#include "comm.h"
/*****************************************************************************
* Local declarations
*****************************************************************************/
int i_comm_fd = -1;
/*****************************************************************************
* comm_Open
*****************************************************************************/
void comm_Open( void )
{
int i_mask;
int i_size = 65535;
struct sockaddr_un sun_server;
if ( (i_comm_fd = socket( AF_UNIX, SOCK_DGRAM, 0 )) == -1 )
{
msg_Err( NULL, "cannot create comm socket (%s)", strerror(errno) );
return;
}
setsockopt( i_comm_fd, SOL_SOCKET, SO_RCVBUF, &i_size, sizeof(i_size) );
memset( &sun_server, 0, sizeof(sun_server) );
sun_server.sun_family = AF_UNIX;
strncpy( sun_server.sun_path, psz_srv_socket, sizeof(sun_server.sun_path) );
sun_server.sun_path[sizeof(sun_server.sun_path) - 1] = '\0';
i_mask = umask(077);
if ( bind( i_comm_fd, (struct sockaddr *)&sun_server,
SUN_LEN(&sun_server) ) < 0 )
{
msg_Err( NULL, "cannot bind comm socket (%s)", strerror(errno) );
umask( i_mask );
close( i_comm_fd );
i_comm_fd = -1;
return;
}
umask( i_mask );
}
/*****************************************************************************
* comm_Read
*****************************************************************************/
void comm_Read( void )
{
struct sockaddr_un sun_client;
socklen_t sun_length = sizeof(sun_client);
ssize_t i_size, i_answer_size = 0;
uint8_t p_buffer[COMM_BUFFER_SIZE], p_answer[COMM_BUFFER_SIZE];
uint8_t i_command, i_answer;
i_size = recvfrom( i_comm_fd, p_buffer, COMM_BUFFER_SIZE, 0,
(struct sockaddr *)&sun_client, &sun_length );
if ( i_size < COMM_HEADER_SIZE )
{
msg_Err( NULL, "cannot read comm socket (%d:%s)\n", i_size,
strerror(errno) );
return;
}
if ( p_buffer[0] != COMM_HEADER_MAGIC )
{
msg_Err( NULL, "wrong protocol version 0x%x", p_buffer[0] );
return;
}
i_command = p_buffer[1];
switch ( i_command )
{
case CMD_RELOAD:
b_hup_received = 1;
i_answer = RET_OK;
i_answer_size = 0;
break;
case CMD_FRONTEND_STATUS:
i_answer = dvb_FrontendStatus( p_answer + COMM_HEADER_SIZE,
&i_answer_size );
break;
case CMD_MMI_STATUS:
i_answer = en50221_StatusMMI( p_answer + COMM_HEADER_SIZE,
&i_answer_size );
break;
case CMD_MMI_SLOT_STATUS:
i_answer = en50221_StatusMMISlot( p_buffer + COMM_HEADER_SIZE,
i_size - COMM_HEADER_SIZE,
p_answer + COMM_HEADER_SIZE,
&i_answer_size );
break;
case CMD_MMI_OPEN:
i_answer = en50221_OpenMMI( p_buffer + COMM_HEADER_SIZE,
i_size - COMM_HEADER_SIZE );
break;
case CMD_MMI_CLOSE:
i_answer = en50221_CloseMMI( p_buffer + COMM_HEADER_SIZE,
i_size - COMM_HEADER_SIZE );
break;
case CMD_MMI_RECV:
i_answer = en50221_GetMMIObject( p_buffer + COMM_HEADER_SIZE,
i_size - COMM_HEADER_SIZE,
p_answer + COMM_HEADER_SIZE,
&i_answer_size );
break;
case CMD_MMI_SEND:
i_answer = en50221_SendMMIObject( p_buffer + COMM_HEADER_SIZE,
i_size - COMM_HEADER_SIZE );
break;
case CMD_SHUTDOWN:
msg_Err( NULL, "shutdown via comm" );
exit(EXIT_SUCCESS);
/* this is a bit violent, but hey, closing everything cleanly
* would do approximately the same */
default:
msg_Err( NULL, "wrong command %u", i_command );
i_answer = RET_HUH;
i_answer_size = 0;
break;
}
p_answer[0] = COMM_HEADER_MAGIC;
p_answer[1] = i_answer;
p_answer[2] = 0;
p_answer[3] = 0;
msg_Dbg( NULL, "answering %d to %d with size %d", i_answer, i_command,
i_answer_size );
if ( sendto( i_comm_fd, p_answer, i_answer_size + COMM_HEADER_SIZE, 0,
(struct sockaddr *)&sun_client, sun_length ) < 0 )
msg_Err( NULL, "cannot send comm socket (%s)", strerror(errno) );
}
/*****************************************************************************
* comm.h
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id: dvblast.h 3 2005-10-05 12:15:55Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/* DVB Card Drivers */
#include <linux/dvb/version.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/ca.h>
#define COMM_BUFFER_SIZE 4096
#define COMM_HEADER_SIZE 4
#define COMM_HEADER_MAGIC 0x48
#define CMD_RELOAD 1
#define CMD_SHUTDOWN 2
#define CMD_FRONTEND_STATUS 3
#define CMD_MMI_STATUS 4
#define CMD_MMI_SLOT_STATUS 5 /* arg: slot */
#define CMD_MMI_OPEN 6 /* arg: slot */
#define CMD_MMI_CLOSE 7 /* arg: slot */
#define CMD_MMI_RECV 8 /* arg: slot */
#define CMD_MMI_SEND 9 /* arg: slot, en50221_mmi_object_t */
#define RET_OK 0
#define RET_ERR 1
#define RET_FRONTEND_STATUS 2
#define RET_MMI_STATUS 3
#define RET_MMI_SLOT_STATUS 4
#define RET_MMI_RECV 5
#define RET_HUH 255
struct ret_frontend_status
{
struct dvb_frontend_info info;
fe_status_t i_status;
int32_t i_ber, i_strength, i_snr;
};
struct ret_mmi_status
{
ca_caps_t caps;
};
struct ret_mmi_slot_status
{
ca_slot_info_t sinfo;
};
struct ret_mmi_recv
{
en50221_mmi_object_t object;
};
struct cmd_mmi_send
{
uint8_t i_slot;
en50221_mmi_object_t object;
};
This diff is collapsed.
This diff is collapsed.
/*****************************************************************************
* dvblast.c
*****************************************************************************
* Copyright (C) 2004, 2008-2009 the VideoLAN team
* $Id: dvblast.c 11 2007-08-09 18:54:37Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include "dvblast.h"
/*****************************************************************************
* Local declarations
*****************************************************************************/
output_t **pp_outputs = NULL;
int i_nb_outputs = 0;
output_t output_dup = { 0 };
static char *psz_conf_file = NULL;
char *psz_srv_socket = NULL;
int i_ttl = 64;
in_addr_t i_ssrc = 0;
static int i_priority = -1;
int i_adapter = 0;
int i_frequency = 0;
int i_srate = 27500000;
int i_voltage = 13;
int b_tone = 0;
int i_bandwidth = 8;
char *psz_modulation = NULL;
int b_budget_mode = 0;
volatile int b_hup_received = 0;
/*****************************************************************************
* Configuration files
*****************************************************************************/
static void ReadConfiguration( char *psz_file )
{
FILE *p_file;
char psz_line[2048];
int i;
if ( (p_file = fopen( psz_file, "r" )) == NULL )
{
msg_Err( NULL, "can't fopen config file %s", psz_file );
return;
}
while ( fgets( psz_line, sizeof(psz_line), p_file ) != NULL )
{
output_t *p_output = NULL;
char *psz_parser, *psz_token, *psz_token2;
struct in_addr maddr;
uint16_t i_port = DEFAULT_PORT;
uint16_t i_sid = 0;
uint16_t *pi_pids = NULL;
int i_nb_pids = 0;
int b_watch;
psz_token = strtok_r( psz_line, "\t\n ", &psz_parser );
if ( psz_token == NULL )
continue;
if ( (psz_token2 = strrchr( psz_token, ':' )) != NULL )
{
*psz_token2 = '\0';
i_port = atoi( psz_token2 + 1 );
}
if ( !inet_aton( psz_token, &maddr ) )
continue;
psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
if ( psz_token == NULL )
continue;
b_watch = atoi( psz_token );
psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
if ( psz_token == NULL )
continue;
i_sid = strtol(psz_token, NULL, 0);
psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
if ( psz_token != NULL )
{
psz_parser = NULL;
for ( ; ; )
{
psz_token = strtok_r( psz_token, ",", &psz_parser );
if ( psz_token == NULL )
break;
pi_pids = realloc( pi_pids,
(i_nb_pids + 1) * sizeof(uint16_t) );
pi_pids[i_nb_pids++] = strtol(psz_token, NULL, 0);
psz_token = NULL;
}
}
msg_Dbg( NULL, "conf: %s:%u w=%d sid=%d pids[%d]=%d,%d,%d,%d,%d...",
inet_ntoa( maddr ), i_port, b_watch, i_sid, i_nb_pids,
i_nb_pids < 1 ? -1 : pi_pids[0],
i_nb_pids < 2 ? -1 : pi_pids[1],
i_nb_pids < 3 ? -1 : pi_pids[2],
i_nb_pids < 4 ? -1 : pi_pids[3],
i_nb_pids < 5 ? -1 : pi_pids[4] );
for ( i = 0; i < i_nb_outputs; i++ )
{
if ( pp_outputs[i]->i_maddr == maddr.s_addr
&& pp_outputs[i]->i_port == i_port )
{
p_output = pp_outputs[i];
break;
}
}
if ( i == i_nb_outputs )
p_output = output_Create( maddr.s_addr, i_port );
if ( p_output != NULL )
{
demux_Change( p_output, i_sid, pi_pids, i_nb_pids );
p_output->b_watch = (b_watch == 1);
p_output->b_still_present = 1;
}
free( pi_pids );
}
fclose( p_file );
for ( i = 0; i < i_nb_outputs; i++ )
{
if ( pp_outputs[i]->i_maddr && !pp_outputs[i]->b_still_present )
{
struct in_addr s;
s.s_addr = pp_outputs[i]->i_maddr;
msg_Dbg( NULL, "closing %s:%u", inet_ntoa( s ),
pp_outputs[i]->i_port );
demux_Change( pp_outputs[i], 0, NULL, 0 );
output_Close( pp_outputs[i] );
}
pp_outputs[i]->b_still_present = 0;
}
}
/*****************************************************************************
* Signal Handler
*****************************************************************************/
static void SigHandler( int i_signal )
{
b_hup_received = 1;
}
/*****************************************************************************
* Entry point
*****************************************************************************/
void usage()
{
msg_Err( NULL, "Usage: dvblast -c <config file> [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] [-i <RT priority>] [-a <adapter>] -f <frequency> [-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-m <modulation] [-u] [-d <dest IP:port>]" );
msg_Err( NULL, "-v: voltage to apply to the LNB (QPSK)" );
msg_Err( NULL, "-p: force 22kHz pulses for high-band selection (DVB-S)" );
msg_Err( NULL, "-m: DVB-C qpsk|qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
msg_Err( NULL, " DVB-T qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
msg_Err( NULL, " DVB-S2 qpsk|psk_8 (default legacy DVB-S)" );
msg_Err( NULL, "-u: turn on budget mode (no hardware PID filtering)" );
msg_Err( NULL, "-d: duplicate all received packets to a given port" );
exit(1);
}
int main( int i_argc, char **pp_argv )
{
struct sched_param param;
int i_error;
if ( i_argc == 1 )
usage();
msg_Err( NULL, "restarting" );
for ( ; ; )
{
char c;
if ( (c = getopt(i_argc, pp_argv, "c:r:t:o:i:a:f:s:v:pb:m:ud:h")) == -1 )
break;
switch ( c )
{
case 'c':
psz_conf_file = optarg;
break;
case 'r':
psz_srv_socket = optarg;
break;
case 't':
i_ttl = strtol( optarg, NULL, 0 );
break;
case 'o':
{
struct in_addr maddr;
if ( !inet_aton( optarg, &maddr ) )
usage();
i_ssrc = maddr.s_addr;
break;
}
case 'i':
i_priority = strtol( optarg, NULL, 0 );
break;
case 'a':
i_adapter = strtol( optarg, NULL, 0 );
break;
case 'f':
i_frequency = strtol( optarg, NULL, 0 );
break;
case 's':
i_srate = strtol( optarg, NULL, 0 );
break;
case 'v':
i_voltage = strtol( optarg, NULL, 0 );
break;
case 'p':
b_tone = 1;
break;
case 'b':
i_bandwidth = strtol( optarg, NULL, 0 );
break;
case 'm':
psz_modulation = optarg;
break;
case 'u':
b_budget_mode = 1;
break;
case 'd':
{
char *psz_token;
uint16_t i_port = DEFAULT_PORT;
struct in_addr maddr;
if ( (psz_token = strrchr( optarg, ':' )) != NULL )
{
*psz_token = '\0';
i_port = atoi( psz_token + 1 );
}
if ( !inet_aton( optarg, &maddr ) )
usage();
output_Init( &output_dup, maddr.s_addr, i_port );
break;
}
case 'h':
default:
usage();
}
}
signal( SIGHUP, SigHandler );
srand( time(NULL) * getpid() );
demux_Open();
if ( i_priority > 0 )
{
memset( &param, 0, sizeof(struct sched_param) );
param.sched_priority = i_priority;
if ( (i_error = pthread_setschedparam( pthread_self(), SCHED_RR,
&param )) )
{
msg_Warn( NULL, "couldn't set thread priority: %s",
strerror(i_error) );
}
}
ReadConfiguration( psz_conf_file );
if ( psz_srv_socket != NULL )
comm_Open();
for ( ; ; )
{
if ( b_hup_received )
{
b_hup_received = 0;
msg_Warn( NULL, "HUP received, reloading" );
ReadConfiguration( psz_conf_file );
}
demux_Run();
}
}
/*****************************************************************************
* dvblast.h
*****************************************************************************
* Copyright (C) 2004, 2008-2009 the VideoLAN team
* $Id: dvblast.h 3 2005-10-05 12:15:55Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <dvbpsi/dvbpsi.h>
#include <dvbpsi/descriptor.h>
#include <dvbpsi/pmt.h>
#define DEFAULT_PORT 3001
#define TS_SIZE 188
#define NB_BLOCKS 7
#define RTP_SIZE 12
#define EMPTY_PID 8192
#define PADDING_PID 8191
#define WATCHDOG_WAIT 10000000LL
#define MAX_ERRORS 100000
typedef int64_t mtime_t;
typedef struct block_t
{
uint8_t p_ts[TS_SIZE];
int i_refcount;
struct block_t *p_next;
} block_t;
typedef struct output_t
{
in_addr_t i_maddr;
uint16_t i_port;
/* output */
int i_handle;
block_t *pp_blocks[NB_BLOCKS];
int i_depth;
uint16_t i_cc;
mtime_t i_ref_timestamp;
mtime_t i_ref_wallclock;
/* demux */
int i_nb_errors;
mtime_t i_last_error;
int b_valid;
dvbpsi_psi_section_t *p_pat_section;
uint8_t i_pat_version, i_pat_cc;
dvbpsi_psi_section_t *p_pmt_section;
uint8_t i_pmt_version, i_pmt_cc;
/* configuration */
uint16_t i_sid; /* 0 if raw mode */
uint16_t *pi_pids;
int i_nb_pids;
int b_watch;
int b_still_present;
} output_t;
extern output_t **pp_outputs;
extern int i_nb_outputs;
extern output_t output_dup;
extern char *psz_srv_socket;
extern int i_ttl;
extern in_addr_t i_ssrc;
extern int i_adapter;
extern int i_frequency;
extern int i_srate;
extern int i_voltage;
extern int b_tone;
extern int i_bandwidth;
extern char *psz_modulation;
extern int b_budget_mode;
extern volatile int b_hup_received;
extern mtime_t i_ca_timeout;
extern int i_comm_fd;
/*****************************************************************************
* Prototypes
*****************************************************************************/
void msg_Info( void *_unused, const char *psz_format, ... );
void msg_Err( void *_unused, const char *psz_format, ... );
void msg_Warn( void *_unused, const char *psz_format, ... );
void msg_Dbg( void *_unused, const char *psz_format, ... );
mtime_t mdate( void );
void msleep( mtime_t delay );
void dvb_Open( void );
block_t * dvb_Read( void );
int dvb_SetFilter( uint16_t i_pid );
void dvb_UnsetFilter( int i_fd, uint16_t i_pid );
uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size );
void demux_Open( void );
void demux_Run( void );
void demux_Change( output_t *p_output, uint16_t i_sid,
uint16_t *pi_pids, int i_nb_pids );
void demux_ResendCAPMTs( void );
int PIDIsSelected( uint16_t i_pid );
output_t *output_Create( in_addr_t i_maddr, uint16_t i_port );
int output_Init( output_t *p_output, in_addr_t i_maddr, uint16_t i_port );
void output_Close( output_t *p_output );
void output_Put( output_t *p_output, block_t *p_block );
void comm_Open( void );
void comm_Read( void );
/*****************************************************************************
* block_New
*****************************************************************************/
static inline block_t *block_New( void )
{
block_t *p_block = malloc(sizeof(block_t));
p_block->p_next = NULL;
p_block->i_refcount = 1;
return p_block;
}
/*****************************************************************************
* block_Delete
*****************************************************************************/
static inline void block_Delete( block_t *p_block )
{
free( p_block );
}
/*****************************************************************************
* block_DeleteChain
*****************************************************************************/
static inline void block_DeleteChain( block_t *p_block )
{
while ( p_block != NULL )
{
block_t *p_next = p_block->p_next;
free( p_block );
p_block = p_next;
}
}
/*****************************************************************************
* block_GetSync
*****************************************************************************/
static inline uint8_t block_GetSync( block_t *p_block )
{
return p_block->p_ts[0];
}
/*****************************************************************************
* block_HasTransportError
*****************************************************************************/
static inline uint8_t block_HasTransportError( block_t *p_block )
{
return p_block->p_ts[1] & 0x80;
}
/*****************************************************************************
* block_UnitStart
*****************************************************************************/
static inline uint8_t block_UnitStart( block_t *p_block )
{
return p_block->p_ts[1] & 0x40;
}
/*****************************************************************************
* block_GetPID
*****************************************************************************/
static inline uint16_t block_GetPID( block_t *p_block )
{
return (((uint16_t)p_block->p_ts[1] & 0x1f) << 8)
| p_block->p_ts[2];
}
/*****************************************************************************
* block_GetScrambling
*****************************************************************************/
static inline uint8_t block_GetScrambling( block_t *p_block )
{
return p_block->p_ts[3] & 0xc0;
}
/*****************************************************************************
* block_GetCC
*****************************************************************************/
static inline uint8_t block_GetCC( block_t *p_block )
{
return p_block->p_ts[3] & 0xf;
}
/*****************************************************************************
* block_HasPCR
*****************************************************************************/
static inline int block_HasPCR( block_t *p_block )
{
return ( p_block->p_ts[3] & 0x20 ) && /* adaptation field present */
( p_block->p_ts[4] >= 7 ) && /* adaptation field size */
( p_block->p_ts[5] & 0x10 ); /* has PCR */
}
/*****************************************************************************
* block_GetPCR
*****************************************************************************/
static inline mtime_t block_GetPCR( block_t *p_block )
{
return ( (mtime_t)p_block->p_ts[6] << 25 ) |
( (mtime_t)p_block->p_ts[7] << 17 ) |
( (mtime_t)p_block->p_ts[8] << 9 ) |
( (mtime_t)p_block->p_ts[9] << 1 ) |
( (mtime_t)p_block->p_ts[10] >> 7 );
}
/*****************************************************************************
* block_GetPayload
*****************************************************************************/
static inline uint8_t *block_GetPayload( block_t *p_block )
{
if ( !(p_block->p_ts[3] & 0x10) )
return NULL;
if ( !(p_block->p_ts[3] & 0x20) )
return &p_block->p_ts[4];
return &p_block->p_ts[ 5 + p_block->p_ts[4] ];
}
#!/bin/sh
###############################################################################
# dvblast_mmi.sh
###############################################################################
# Copyright (C) 1998-2008 the VideoLAN team
# $Id: ead45da90b964b384dd20bfad15b7233e7243c66 $
#
# Authors: Christophe Massiot <massiot@via.ecp.fr>
#
# 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
###############################################################################
BASE_DIR=`dirname $_`
#
# Check args
#
if test x"$1" != x"-r" -o -z "$2"; then
echo "Usage: $0 -r <remote socket> [<slot 0-n>]" >&2
exit 1
fi
SOCKET=$2
SLOT=$3
if which dvblastctl >/dev/null; then
DVBLASTCTL="dvblastctl -r $SOCKET"
elif test -x "$PWD/dvblastctl"; then
DVBLASTCTL="$PWD/dvblastctl -r $SOCKET"
elif test -x "$BASE_DIR/dvblastctl"; then
DVBLASTCTL="$BASE_DIR/dvblastctl -r $SOCKET"
else
echo "Couldn't find dvblastctl"
exit 1
fi
#
# Check adapter status
#
$DVBLASTCTL mmi_status >/dev/null
NUM_SLOTS=$?
if test $NUM_SLOTS -eq 255; then
echo "Unable to set up a connection" >&2
exit 2
fi
if test $NUM_SLOTS -eq 0; then
echo "Adapter has no available CAM module" >&2
exit 3
fi
if test -z $SLOT; then
echo "Defaulting to slot #0"
SLOT=0
fi
if test "$SLOT" -ge $NUM_SLOTS; then
echo "Slot out of range, pick in the range 0-`expr $NUM_SLOTS - 1`" >&2
exit 3
fi
#
# Check CAM status
#
$DVBLASTCTL mmi_slot_status $SLOT >/dev/null
STATUS=$?
if test $STATUS -ne 0; then
echo "Slot is not ready, retry later" >&2
exit 3
fi
$DVBLASTCTL mmi_get $SLOT >/dev/null
STATUS=$?
if test $STATUS -eq 255; then
echo "Opening MMI session..."
$DVBLASTCTL mmi_open $SLOT
STATUS=$?
if test $STATUS -eq 255; then
echo "Communication error" >&2
exit 2
elif test $STATUS -ne 0; then
echo "Couldn't open MMI session" >&2
exit 4
fi
sleep 3
fi
#
# Da loop
#
while :; do
$DVBLASTCTL mmi_get $SLOT
STATUS=$?
case $STATUS in
255)
echo "Connection closed" >&2
exit 2
;;
254)
echo -n "Your choice (empty for extra choices) ? "
;;
253)
echo "CAUTION: the password won't be bulleted, be alone"
echo -n "Your choice (empty for extra choices) ? "
;;
0)
echo -n "Your choice: (B)ack, (C)lose or (R)etry ? "
;;
*)
echo -n "Your choice: [0-$STATUS], (C)lose or (R)etry ? "
;;
esac
read -r ANSWER
case $STATUS in
254|253)
if test -z "$ANSWER"; then
echo -n "(B)ack, (C)lose or (R)etry ? "
read -r ANSWER
case "$ANSWER" in
B|b|Back|back|BACK)
if ! $DVBLASTCTL mmi_send_text $SLOT; then
echo "mmi_send_text failed, apparently" >&2
else
sleep 1
fi
;;
C|c|Close|close|CLOSE)
$DVBLASTCTL mmi_close $SLOT
exit 0
;;
R|r|Retry|retry|RETRY)
:
;;
*)
echo "Invalid string, retry..."
;;
esac
else
if ! $DVBLASTCTL mmi_send_text $SLOT "$ANSWER"; then
echo "mmi_send_text failed, apparently" >&2
else
sleep 1
fi
fi
;;
*)
case "$ANSWER" in
B|b|Back|back|BACK)
if ! $DVBLASTCTL mmi_send_choice $SLOT 0; then
echo "mmi_send_choice failed, apparently" >&2
else
sleep 1
fi
;;
C|c|Close|close|CLOSE)
$DVBLASTCTL mmi_close $SLOT
exit 0
;;
R|r|Retry|retry|RETRY)
:
;;
*)
echo "$ANSWER" | grep -q "^[[:digit:]]\+\$"
if test $? -ne 0; then
echo "Invalid string, retry..."
else
if ! $DVBLASTCTL mmi_send_choice $SLOT "$ANSWER"; then
echo "mmi_send_choice failed, apparently" >&2
else
sleep 1
fi
fi
;;
esac
;;
esac
echo
done
This diff is collapsed.
This diff is collapsed.
/*****************************************************************************
* en50221.h
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id: dvblast.h 3 2005-10-05 12:15:55Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <malloc.h>
typedef void * access_t;
#define STRINGIFY( z ) UGLY_KLUDGE( z )
#define UGLY_KLUDGE( z ) #z
#define EN50221_MMI_NONE 0
#define EN50221_MMI_ENQ 1
#define EN50221_MMI_ANSW 2
#define EN50221_MMI_MENU 3
#define EN50221_MMI_MENU_ANSW 4
#define EN50221_MMI_LIST 5
typedef struct en50221_mmi_object_t
{
int i_object_type;
union
{
struct
{
int b_blind;
char *psz_text;
} enq;
struct
{
int b_ok;
char *psz_answ;
} answ;
struct
{
char *psz_title, *psz_subtitle, *psz_bottom;
char **ppsz_choices;
int i_choices;
} menu; /* menu and list are the same */
struct
{
int i_choice;
} menu_answ;
} u;
} en50221_mmi_object_t;
#define MAX_CI_SLOTS 16
#define MAX_SESSIONS 32
#define MAX_PROGRAMS 24
extern int i_ca_handle;
extern int i_ca_type;
/*****************************************************************************
* Prototypes
*****************************************************************************/
void en50221_Init( void );
void en50221_Reset( void );
void en50221_Poll( void );
void en50221_AddPMT( dvbpsi_pmt_t *p_pmt );
void en50221_UpdatePMT( dvbpsi_pmt_t *p_pmt );
void en50221_DeletePMT( dvbpsi_pmt_t *p_pmt );
uint8_t en50221_StatusMMI( uint8_t *p_answer, ssize_t *pi_size );
uint8_t en50221_StatusMMISlot( uint8_t *p_buffer, ssize_t i_size,
uint8_t *p_answer, ssize_t *pi_size );
uint8_t en50221_OpenMMI( uint8_t *p_buffer, ssize_t i_size );
uint8_t en50221_CloseMMI( uint8_t *p_buffer, ssize_t i_size );
uint8_t en50221_GetMMIObject( uint8_t *p_buffer, ssize_t i_size,
uint8_t *p_answer, ssize_t *pi_size );
uint8_t en50221_SendMMIObject( uint8_t *p_buffer, ssize_t i_size );
/*
* This is where it gets scary: do not show to < 18 yrs old
*/
/*****************************************************************************
* en50221_SerializeMMIObject :
*****************************************************************************/
static inline int en50221_SerializeMMIObject( uint8_t *p_answer,
ssize_t *pi_size,
en50221_mmi_object_t *p_object )
{
ssize_t i_max_size = *pi_size;
en50221_mmi_object_t *p_serialized = (en50221_mmi_object_t *)p_answer;
char **pp_tmp;
int i;
#define STORE_MEMBER(pp_pointer, i_size) \
if ( i_size + *pi_size > i_max_size ) \
return -1; \
memcpy( p_answer, *pp_pointer, i_size ); \
*pp_pointer = (void *)*pi_size; \
*pi_size += i_size; \
p_answer += i_size;
if ( sizeof(en50221_mmi_object_t) > i_max_size )
return -1;
memcpy( p_answer, p_object, sizeof(en50221_mmi_object_t) );
*pi_size = sizeof(en50221_mmi_object_t);
p_answer += sizeof(en50221_mmi_object_t);
switch ( p_object->i_object_type )
{
case EN50221_MMI_ENQ:
STORE_MEMBER( &p_serialized->u.enq.psz_text,
strlen(p_object->u.enq.psz_text) + 1 );
break;
case EN50221_MMI_ANSW:
STORE_MEMBER( &p_serialized->u.answ.psz_answ,
strlen(p_object->u.answ.psz_answ) + 1 );
break;
case EN50221_MMI_MENU:
case EN50221_MMI_LIST:
STORE_MEMBER( &p_serialized->u.menu.psz_title,
strlen(p_object->u.menu.psz_title) + 1 );
STORE_MEMBER( &p_serialized->u.menu.psz_subtitle,
strlen(p_object->u.menu.psz_subtitle) + 1 );
STORE_MEMBER( &p_serialized->u.menu.psz_bottom,
strlen(p_object->u.menu.psz_bottom) + 1 );
/* pointer alignment */
i = ((*pi_size + 7) / 8) * 8 - *pi_size;
*pi_size += i;
p_answer += i;
pp_tmp = (char **)p_answer;
STORE_MEMBER( &p_serialized->u.menu.ppsz_choices,
p_object->u.menu.i_choices * sizeof(char *) );
for ( i = 0; i < p_object->u.menu.i_choices; i++ )
{
STORE_MEMBER( &pp_tmp[i],
strlen(p_object->u.menu.ppsz_choices[i]) + 1 );
}
break;
default:
break;
}
return 0;
}
/*****************************************************************************
* en50221_UnserializeMMIObject :
*****************************************************************************/
static inline int en50221_UnserializeMMIObject( en50221_mmi_object_t *p_object,
ssize_t i_size )
{
int i, j;
#define CHECK_MEMBER(pp_member) \
if ( (ptrdiff_t)*pp_member >= i_size ) \
return -1; \
for ( i = 0; ((char *)p_object + (ptrdiff_t)*pp_member)[i] != '\0'; \
i++ ) \
if ( (ptrdiff_t)*pp_member + i >= i_size ) \
return -1; \
*pp_member += (ptrdiff_t)p_object;
switch ( p_object->i_object_type )
{
case EN50221_MMI_ENQ:
CHECK_MEMBER(&p_object->u.enq.psz_text);
break;
case EN50221_MMI_ANSW:
CHECK_MEMBER(&p_object->u.answ.psz_answ);
break;
case EN50221_MMI_MENU:
case EN50221_MMI_LIST:
CHECK_MEMBER(&p_object->u.menu.psz_title);
CHECK_MEMBER(&p_object->u.menu.psz_subtitle);
CHECK_MEMBER(&p_object->u.menu.psz_bottom);
if ( (ptrdiff_t)p_object->u.menu.ppsz_choices
+ p_object->u.menu.i_choices * sizeof(char *) >= i_size )
return -1;
p_object->u.menu.ppsz_choices = (char **)((char *)p_object
+ (ptrdiff_t)p_object->u.menu.ppsz_choices);
for ( j = 0; j < p_object->u.menu.i_choices; j++ )
{
CHECK_MEMBER(&p_object->u.menu.ppsz_choices[j]);
}
break;
default:
break;
}
return 0;
}
/*****************************************************************************
* output.c
*****************************************************************************
* Copyright (C) 2004, 2008-2009 the VideoLAN team
* $Id: output.c 2 2005-09-23 19:06:05Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <errno.h>
#include "dvblast.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int net_Open( output_t *p_output );
static void rtp_SetHdr( output_t *p_output, uint8_t *p_hdr );
/*****************************************************************************
* output_Create : called from main thread
*****************************************************************************/
output_t *output_Create( in_addr_t i_maddr, uint16_t i_port )
{
int i;
output_t *p_output = NULL;
for ( i = 0; i < i_nb_outputs; i++ )
{
if ( !pp_outputs[i]->i_maddr )
{
p_output = pp_outputs[i];
break;
}
}
if ( p_output == NULL )
{
p_output = malloc( sizeof(output_t) );
memset( p_output, 0, sizeof(output_t) );
i_nb_outputs++;
pp_outputs = realloc( pp_outputs, i_nb_outputs * sizeof(output_t *) );
pp_outputs[i] = p_output;
}
if ( output_Init( p_output, i_maddr, i_port ) < 0 )
return NULL;
return p_output;
}
/*****************************************************************************
* output_Init
*****************************************************************************/
int output_Init( output_t *p_output, in_addr_t i_maddr, uint16_t i_port )
{
p_output->i_sid = 0;
p_output->i_depth = 0;
p_output->pi_pids = NULL;
p_output->i_nb_pids = 0;
p_output->i_nb_errors = 0;
p_output->i_cc = rand() & 0xffff;
p_output->i_pat_cc = rand() & 0xf;
p_output->i_pmt_cc = rand() & 0xf;
p_output->i_pat_version = rand() & 0xff;
p_output->i_pmt_version = rand() & 0xff;
p_output->p_pat_section = NULL;
p_output->p_pmt_section = NULL;
p_output->i_ref_timestamp = 0;
p_output->i_ref_wallclock = mdate();
p_output->i_maddr = i_maddr;
p_output->i_port = i_port;
if ( (p_output->i_handle = net_Open(p_output)) < 0 )
{
p_output->i_maddr = 0;
return -1;
}
return 0;
}
/*****************************************************************************
* output_Close
*****************************************************************************/
void output_Close( output_t *p_output )
{
int i;
for ( i = 0; i < p_output->i_depth; i++ )
{
p_output->pp_blocks[i]->i_refcount--;
if ( !p_output->pp_blocks[i]->i_refcount )
block_Delete( p_output->pp_blocks[i] );
}
p_output->i_depth = 0;
p_output->i_maddr = 0;
close( p_output->i_handle );
}
/*****************************************************************************
* output_Flush
*****************************************************************************/
static void output_Flush( output_t *p_output )
{
struct iovec p_iov[NB_BLOCKS + 1];
uint8_t p_rtp_hdr[RTP_SIZE];
int i;
p_iov[0].iov_base = p_rtp_hdr;
p_iov[0].iov_len = sizeof(p_rtp_hdr);
rtp_SetHdr( p_output, p_rtp_hdr );
for ( i = 1; i < NB_BLOCKS + 1; i++ )
{
p_iov[i].iov_base = p_output->pp_blocks[i - 1]->p_ts;
p_iov[i].iov_len = TS_SIZE;
}
if ( writev( p_output->i_handle, p_iov, NB_BLOCKS + 1 ) < 0 )
{
struct in_addr s;
s.s_addr = p_output->i_maddr;
msg_Err( NULL, "coundn't writev to %s:%u (%s)", inet_ntoa( s ),
p_output->i_port, strerror(errno) );
}
for ( i = 0; i < NB_BLOCKS; i++ )
{
p_output->pp_blocks[i]->i_refcount--;
if ( !p_output->pp_blocks[i]->i_refcount )
block_Delete( p_output->pp_blocks[i] );
}
p_output->i_depth = 0;
}
/*****************************************************************************
* output_Put : called from demux
*****************************************************************************/
void output_Put( output_t *p_output, block_t *p_block )
{
p_block->i_refcount++;
p_output->pp_blocks[p_output->i_depth] = p_block;
p_output->i_depth++;
if ( p_output->i_depth >= NB_BLOCKS )
output_Flush( p_output );
}
/*****************************************************************************
* net_Open
*****************************************************************************/
static int net_Open( output_t *p_output )
{
int i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(p_output->i_port);
sin.sin_addr.s_addr = p_output->i_maddr;
if ( connect( i_handle, (struct sockaddr *)&sin, sizeof( sin ) ) < 0 )
{
struct in_addr s;
s.s_addr = p_output->i_maddr;
msg_Err( NULL, "couldn't connect to %s:%u (%s)", inet_ntoa( s ),
p_output->i_port, strerror(errno) );
close( i_handle );
return -1;
}
if ( IN_MULTICAST( ntohl(p_output->i_maddr) ) )
{
int i = i_ttl;
setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
(void *)&i, sizeof(i) );
}
return i_handle;
}
/*****************************************************************************
* rtp_SetHdr
*****************************************************************************/
/*
* Reminder : RTP header
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static void rtp_SetHdr( output_t *p_output, uint8_t *p_hdr )
{
mtime_t i_timestamp = p_output->i_ref_timestamp
+ (mdate() - p_output->i_ref_wallclock) * 9 / 100;
p_hdr[0] = 0x80;
p_hdr[1] = 33;
p_hdr[2] = p_output->i_cc >> 8;
p_hdr[3] = p_output->i_cc & 0xff;
p_hdr[4] = (i_timestamp >> 24) & 0xff;
p_hdr[5] = (i_timestamp >> 16) & 0xff;
p_hdr[6] = (i_timestamp >> 8) & 0xff;
p_hdr[7] = i_timestamp & 0xff;
p_hdr[8] = ((uint8_t *)&i_ssrc)[0];
p_hdr[9] = ((uint8_t *)&i_ssrc)[1];
p_hdr[10] = ((uint8_t *)&i_ssrc)[2];
p_hdr[11] = ((uint8_t *)&i_ssrc)[3];
p_output->i_cc++;
}
/*****************************************************************************
* util.c
*****************************************************************************
* Copyright (C) 2004 the VideoLAN team
* $Id: util.c 9 2007-03-15 16:58:05Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* 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 Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "dvblast.h"
/*****************************************************************************
* Local declarations
*****************************************************************************/
#define MAX_MSG 1024
/*****************************************************************************
* msg_Info
*****************************************************************************/
void msg_Info( void *_unused, const char *psz_format, ... )
{
va_list args;
char psz_fmt[MAX_MSG];
va_start( args, psz_format );
snprintf( psz_fmt, MAX_MSG, "dvblast info: %s\n", psz_format );
vfprintf( stderr, psz_fmt, args );
}
/*****************************************************************************
* msg_Err
*****************************************************************************/
void msg_Err( void *_unused, const char *psz_format, ... )
{
va_list args;
char psz_fmt[MAX_MSG];
va_start( args, psz_format );
snprintf( psz_fmt, MAX_MSG, "dvblast error: %s\n", psz_format );
vfprintf( stderr, psz_fmt, args );
}
/*****************************************************************************
* msg_Warn
*****************************************************************************/
void msg_Warn( void *_unused, const char *psz_format, ... )
{
va_list args;
char psz_fmt[MAX_MSG];
va_start( args, psz_format );
snprintf( psz_fmt, MAX_MSG, "dvblast warning: %s\n", psz_format );
vfprintf( stderr, psz_fmt, args );
}
/*****************************************************************************
* msg_Dbg
*****************************************************************************/
void msg_Dbg( void *_unused, const char *psz_format, ... )
{
va_list args;
char psz_fmt[MAX_MSG];
va_start( args, psz_format );
snprintf( psz_fmt, MAX_MSG, "dvblast debug: %s\n", psz_format );
vfprintf( stderr, psz_fmt, args );
}
/*****************************************************************************
* mdate
*****************************************************************************/
mtime_t mdate( void )
{
struct timeval tv_date;
/* gettimeofday() could return an error, and should be tested. However, the
* only possible error, according to 'man', is EFAULT, which can not happen
* here, since tv is a local variable. */
gettimeofday( &tv_date, NULL );
return( (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec );
}
/*****************************************************************************
* msleep
*****************************************************************************/
void msleep( mtime_t delay )
{
struct timespec ts_delay;
ts_delay.tv_sec = delay / 1000000;
ts_delay.tv_nsec = (delay % 1000000) * 1000;
nanosleep( &ts_delay, NULL );
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment