File:
[DVB] /
multiplexer /
splice.c
Revision
1.10:
download - view:
text,
annotated -
select for diffs
Thu Jun 17 22:04:07 2004 UTC (19 years, 11 months ago) by
oskar
Branches:
MAIN
CVS tags:
version-1-1-7,
version-1-1-6,
version-1-1-5,
version-1-1-4,
version-1-1-3,
version-1-1-2,
version-1-1-1,
version-1-1-0,
version-1-0-8,
version-1-0-7,
version-1-0-6,
version-1-0-5,
version-1-0-4,
version-1-0-3,
version-1-0-2,
HEAD
ignore sigpipe
/*
* ISO 13818 stream multiplexer
* Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
* Author: Oskar Schirmer (schirmer@scara.com)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Module: Splice
* Purpose: Service functions for specific Splice* modules
*
* This module provides functions needed for splicing
* which are independent from the splice type.
*/
#include "global.h"
#include "error.h"
#include "splice.h"
#include "input.h"
#include "pes.h"
#include "descref.h"
t_msec next_psi_periodic;
t_msec psi_frequency_msec;
boolean psi_frequency_changed;
int configuration_on;
boolean configuration_changed;
boolean configuration_descr_changed;
const char *configuration_total = "Conf: progs: %d\n";
static modifydescr_descr *globalmodifydescr;
boolean splice_init (void)
{
psi_frequency_msec = 0;
psi_frequency_changed = FALSE;
configuration_on = 0;
globalmodifydescr = NULL;
return (splice_specific_init ());
}
/* Connect a stream with a target program.
* programnb denotes the program to connect,
* stream is the stream to connect,
* all further parameters are as with input_openstream.
* If stream is NULL, open a stream first.
* Add the stream to the programs list of streams and vice versa.
* Precondition: f!=NULL
* Return: the changed stream on success, the unchanged "stream" otherwise
*/
stream_descr *connect_streamprog (file_descr *f,
int programnb,
int sourceid,
int streamid,
int streamtype,
stream_descr *stream,
stream_descr *mapstream,
boolean mention)
{
stream_descr *s;
prog_descr *p;
if (stream == NULL) {
s = input_openstream (f,sourceid,streamid<0?-streamid:streamid,
streamtype,sd_data,mapstream);
} else {
if (streamid < 0) {
streamid = -streamid;
warn (LWAR,"Cannot refind sid",ESPC,1,1,streamid);
}
s = stream;
}
if (s != NULL) {
p = splice_openprog (programnb);
if (p != NULL) {
if (input_addprog (s,p)) {
if (splice_addstream (p,s,streamid>=0) > 0) {
/*
if (p->pcr_pid < 0) {
if (xxx) {
p->pcr_pid = s->u.d.pid;
s->u.d.has_clockref = TRUE;
s->u.d.next_clockref = msec_now () - MAX_MSEC_PCRDIST;
}
}
*/
s->endaction = ENDSTR_WAIT;
s->u.d.mention = mention;
return (s);
}
input_delprog (s,p);
}
if (p->streams <= 0) {
splice_closeprog (p);
}
}
if (stream == NULL) {
input_closestream (s);
}
}
return (stream);
}
/* Unlink a stream from a target program.
* If the stream comes out to be in no program then, close it.
* This function may be used only, if the program in question will either
* be non-empty after the call, or will be closed by the calling function.
* Precondition: s!=NULL, p!=NULL
*/
void unlink_streamprog (stream_descr *s,
prog_descr *p)
{
splice_delstream (p,s);
input_delprog (s,p);
if (s->u.d.progs <= 0) {
file_descr *f;
f = s->fdescr;
input_closestream (s);
input_closefileifunused (f);
}
}
/* Remove a stream from a target program.
* Close stream and/or program, if not contained in another program or stream.
* The input file is no longer automatic, because we do manual changes here.
* Precondition: s!=NULL, p!=NULL, s is stream in target program p
*/
void remove_streamprog (stream_descr *s,
prog_descr *p)
{
s->fdescr->automatic = FALSE;
if (p->streams > 1) {
unlink_streamprog (s,p);
} else {
splice_closeprog (p);
}
}
/* Find the right stream in a program
* Precondition: p!=NULL
* Return: stream, if found, NULL otherwise
*/
stream_descr *get_streamprog (prog_descr *p,
int streamid)
{
int i;
i = p->streams;
while (--i >= 0) {
stream_descr *s;
s = p->stream[i];
if (s->stream_id == streamid) {
return (s);
}
}
return (NULL);
}
/* Find a free stream ID in a program that is equivalent to the given stream id
* Precondition: p!=NULL
* Return: Free ID, if found; given sid otherwise.
*/
int splice_findfreestreamid (prog_descr *p,
int sid)
{
int s0, s, n;
s0 = sid;
if ((sid >= PES_CODE_AUDIO)
&& (sid < (PES_CODE_AUDIO+PES_NUMB_AUDIO))) {
s = PES_CODE_AUDIO;
n = PES_NUMB_AUDIO;
} else if ((sid >= PES_CODE_VIDEO)
&& (sid < (PES_CODE_VIDEO+PES_NUMB_VIDEO))) {
s = PES_CODE_VIDEO;
n = PES_NUMB_VIDEO;
} else {
s = sid;
n = 1;
}
while (--n >= 0) {
int i;
i = p->streams;
while ((--i >= 0)
&& (p->stream[i]->stream_id != s0)) {
}
if (i < 0) {
warn (LIMP,"Found SID free",ESPC,2,sid,s0);
return (s0);
}
s0 = s;
s += 1;
}
warn (LIMP,"Found SID",ESPC,2,sid,sid);
return (sid);
}
/* Check if there is a source pcr stream in a target program
* Precondition: p!=NULL
* Return: pcr-stream, if found; NULL otherwise.
*/
stream_descr *splice_findpcrstream (prog_descr *p)
{
int i;
pmt_descr *pmt;
warn (LIMP,"Find PCR Stream",ESPC,3,0,p->program_number);
i = p->streams;
while (--i >= 0) {
if (p->stream[i]->fdescr->content == ct_transport) {
pmt = p->stream[i]->fdescr->u.ts.pat;
while (pmt != NULL) {
if (pmt->pcr_pid == p->stream[i]->sourceid) {
warn (LIMP,"Found PCR Stream",ESPC,3,1,p->stream[i]->sourceid);
return (p->stream[i]);
}
pmt = pmt->next;
}
}
}
return (NULL);
}
/* Print configuration of descriptors
* Precondition: manud!=NULL
*/
static void splice_descr_configuration (descr_descr *manud,
descr_descr *autod)
{
int i, l;
byte *y;
i = NUMBER_DESCR;
while (--i >= 0) {
y = manud->refx[i];
if (y == NULL) {
if (autod != NULL) {
y = autod->refx[i];
}
} else if (y[1] == 0) {
y = NULL;
}
if (y != NULL) {
l = y[1];
fprintf (stderr, "Conf: descr:%02X len:%d data:", *y++, l);
while (--l >= 0) {
fprintf (stderr, "%02X", *++y);
}
fprintf (stderr, "\n");
}
}
}
/* Print configuration for one program
* Precondition: p!=NULL
*/
void splice_one_configuration (prog_descr *p)
{
int i, s;
stump_descr *st;
i = p->streams;
s = 0;
st = p->stump;
while (st != NULL) {
s += 1;
st = st->next;
}
fprintf (stderr, "Conf: prog:%04X pmt:%04hX pcr:%04hX streams:%2d",
p->program_number, p->pmt_pid, p->pcr_pid, i+s);
if (s > 0) {
fprintf (stderr, " (%d)", s);
}
fprintf (stderr, "\n");
if (configuration_on > 1) {
splice_descr_configuration (&p->manudescr, NULL); /* Missing auto descr! */
}
while (--i >= 0) {
stream_descr *s;
s = p->stream[i];
fprintf (stderr, "Conf: stream:%04hX type:%02X sid:%02X "
"file:%d source:%04hX num:%2d name:%s\n",
s->u.d.pid, s->stream_type, s->stream_id,
s->fdescr->content, s->sourceid, s->fdescr->filerefnum, s->fdescr->name);
if (configuration_on > 1) {
splice_descr_configuration (s->manudescr, s->autodescr);
}
}
st = p->stump;
while (st != NULL) {
fprintf (stderr, "Conf: stream:%04hX type:%02X\n",
st->pid, st->stream_type);
if (configuration_on > 1) {
splice_descr_configuration (&st->manudescr, NULL);
}
st = st->next;
}
}
void splice_set_configuration (int on)
{
configuration_on = on;
configuration_changed = TRUE;
}
static void splice_modifydescriptor (descr_descr *md,
int dtag,
int dlength,
byte *data,
stream_descr *s)
{
int i, j;
byte *t, *u;
if (dtag < 0) {
clear_descrdescr (md);
} else {
t = md->refx[dtag];
if ((dlength < 0)
|| ((t != NULL)
&& (t != &md->null[0]))) {
j = t[1]+2;
i = NUMBER_DESCR;
while (--i >= 0) {
if ((md->refx[i]-t) > 0) {
md->refx[i] -= j;
}
}
memmove (t,&t[j],sizeof(md->data)-(j+(t-&md->data[0])));
}
if (dlength == 0) {
t = &md->null[0];
} else if (dlength < 0) {
t = NULL;
} else {
i = NUMBER_DESCR;
t = &md->data[0];
while (--i >= 0) {
u = md->refx[i];
if (u != NULL) {
u = &u[u[1]+2];
if ((u-t) > 0) {
t = u;
}
}
}
if (t-&md->data[0] < 0) {
warn (LERR,"No space left",ESPC,5,2,t-&md->data[0]);
return;
}
if ((t-&md->data[0]+dlength+2-MAX_PSI_SIZE) > 0) {
warn (LWAR,"No space left",ESPC,5,1,t-&md->data[0]);
return;
}
t[0] = dtag;
t[1] = dlength;
memcpy (&t[2],data,dlength);
}
md->refx[dtag] = t;
}
if (s != NULL) {
i = s->u.d.progs;
while (--i >= 0) {
s->u.d.pdescr[i]->changed = TRUE;
}
}
}
static void splice_modifydescrlater (int programnb,
short sid,
short pid,
int dtag,
int dlength,
byte *data)
{
modifydescr_descr *l;
modifydescr_descr **pl;
pl = &globalmodifydescr;
l = *pl;
while (l != NULL) {
if ((programnb < 0) /* delete older matching entries */
|| ((programnb == l->programnb)
&& ((pid == 0)
|| ((pid == l->pid)
&& (sid == l->sid)
&& ((dtag < 0)
|| (dtag == l->dtag)))))) {
*pl = l->next;
free (l);
} else {
pl = &l->next;
}
l = *pl;
}
if ((dtag >= 0)
&& (dlength >= 0)) { /* don't save modifiers, that delete */
if ((l = malloc (sizeof(modifydescr_descr))) != NULL) {
l->next = NULL;
l->programnb = programnb;
l->sid = sid;
l->pid = pid;
l->dtag = dtag;
l->dlength = dlength;
if (dlength > 0) {
memcpy (&l->data[0],data,dlength);
}
*pl = l; /* append at end of list */
} else {
warn (LERR,"Malloc fail",ETSC,12,1,programnb);
}
}
}
/* For a new program and maybe stream or stump,
* check presence of applicable descriptors, that have been stored.
* All non-NULL parameters must be completely linked into p upon call!
* Precondition: p != NULL
*/
void splice_modifycheckmatch (int programnb,
prog_descr *p,
stream_descr *s,
stump_descr *st)
{
modifydescr_descr *l;
modifydescr_descr **pl;
pl = &globalmodifydescr;
l = *pl;
while (l != NULL) {
if ((programnb == l->programnb)
&& (((l->sid < 0)
&& (l->pid < 0))
|| ((l->pid > 0)
&& (((s != NULL)
&& (l->pid == s->u.d.pid))
|| ((st != NULL)
&& (l->pid = st->pid))))
|| ((l->sid >= 0)
&& (s != NULL)
&& (l->sid == s->stream_id)))) {
splice_modifytargetdescrprog (p,programnb,
l->sid,l->pid,l->dtag,l->dlength,&l->data[0],st);
*pl = l->next;
free (l);
} else {
pl = &l->next;
}
l = *pl;
}
}
/* Modify an entry in a manudescr struct.
*/
void splice_modifytargetdescrprog (prog_descr *p,
int programnb,
short sid,
short pid,
int dtag,
int dlength,
byte *data,
stump_descr *globstump)
{
int i;
stream_descr *s;
stump_descr *st;
if (sid >= 0) {
if (p != NULL) {
i = p->streams;
while (--i >= 0) {
s = p->stream[i];
if (s->stream_id == sid) {
splice_modifydescriptor (s->manudescr,dtag,dlength,data,s);
configuration_descr_changed = TRUE;
return;
}
}
}
splice_modifydescrlater (programnb,sid,pid,dtag,dlength,data);
} else {
if (pid > 0) {
if (p != NULL) {
i = p->streams;
while (--i >= 0) {
s = p->stream[i];
if (s->u.d.pid == pid) {
splice_modifydescriptor (s->manudescr,dtag,dlength,data,s);
configuration_descr_changed = TRUE;
return;
}
}
st = p->stump;
} else {
st = globstump;
}
while (st != NULL) {
if ((st->pid == pid)
&& (st->program_number == programnb)) {
splice_modifydescriptor (&st->manudescr,dtag,dlength,data,NULL);
if (p != NULL) {
p->changed = TRUE;
}
configuration_descr_changed = TRUE;
return;
}
st = st->next;
}
splice_modifydescrlater (programnb,sid,pid,dtag,dlength,data);
} else if (pid < 0) {
if (p != NULL) {
splice_modifydescriptor (&p->manudescr,dtag,dlength,data,NULL);
p->changed = TRUE;
configuration_descr_changed = TRUE;
} else {
splice_modifydescrlater (programnb,sid,pid,dtag,dlength,data);
}
} else {
if (p != NULL) {
i = p->streams;
while (--i >= 0) {
s = p->stream[i];
splice_modifydescriptor (s->manudescr,dtag,dlength,data,s);
}
splice_modifydescriptor (&p->manudescr,dtag,dlength,data,NULL);
configuration_descr_changed = TRUE;
st = p->stump;
} else {
st = globstump;
}
while (st != NULL) {
if (st->program_number == programnb) {
splice_modifydescriptor (&st->manudescr,dtag,dlength,data,NULL);
}
st = st->next;
}
splice_modifydescrlater (programnb,sid,pid,dtag,dlength,data);
}
}
}
LinuxTV legacy CVS <linuxtv.org/cvs>