⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpeg2pat.c

📁 Sun公司Dream项目
💻 C
字号:
/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the "License").  You may not use this file except
 * in compliance with the License.
 *
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.php
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * HEADER in each file and include the License file at
 * http://www.opensource.org/licenses/cddl1.php.  If 
 * applicable, add the following below this CDDL HEADER, 
 * with the fields enclosed by brackets "[]" replaced 
 * with your own identifying information: 
 * Portions Copyright [yyyy]
 * [name of copyright owner]
 */ 

/*
 * $(@)Mpeg2Pat.c $Revision: 1.1.1.1 $ $Date: 2006/04/17 22:47:31 $
 * 
 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
 */
/*
 * Copyright (c) 1996 by Sun Microsystems, Inc.
 */

/*
 * MPEG2 program association table parser
 */

#pragma ident "@(#)Mpeg2Pat.c 1.2	97/05/20 SMI"

#include <string.h>
#include <stdlib.h>

#include "cobjs/Log.h"
#include "cobjs/Macros.h"
#include "cobjs/Types.h"
#include "cobjs/RetCode.h"

#include "mmp/Mmp.h"
#include "mmp/Pipe.h"

#include "mmp/Mpeg2Pat.h"

#define	MPEG2_PAT_MAX_CHUNK		256

struct _Mpeg2Pat {
    MmpParserObject    *netPop;
    MmpParserObject    *psiPop;
    Mpeg2PatCallBack    callBack;
    void               *token;
    Mpeg2PatTable       pat[2];
    MmpParserObject     po;
    Boolean		isDirty;
};

static size_t       mpeg2PatMaxChunk(void *instp);

static RetCode
mpeg2PatParse(void *instp, MmpContextObject *cop,
	      Pipe pipe);

static void         mpeg2PatRecover(void *instp);

static RetCode
mpeg2PatActivate(Mpeg2Pat mpeg2Pat, MmpContextObject *cop,
		 Mpeg2PatTable *patp, unsigned sectionNumber,
		 Mpeg2PatSection *psp);

static RetCode
mpeg2PatPromote(Mpeg2Pat mpeg2Pat, MmpContextObject *cop);

static void         mpeg2PatDeactivate(Mpeg2PatTable *patp);

static RetCodeTable mpeg2PatErrorTable[] = {
    {MPEG2_PAT_ERROR_SSI, NULL, "section syntax indicator not set"},
    {MPEG2_PAT_ERROR_SN, NULL, "section number > last section number"},
    {MPEG2_PAT_ERROR_PID, NULL, "PAT found on non-zero pid"},
    {MPEG2_PAT_ERROR_LSN, NULL, "last section number changed within version"},
    {MPEG2_PAT_ERROR_SL, NULL, "pat section too long"},
    {MPEG2_PAT_ERROR_LEN, NULL, "pat section length error"},
    {MPEG2_PAT_ERROR_CRC, NULL, "crc error"},
    {MPEG2_PAT_ERROR_MISMATCH, NULL, "section changed without new version"},
    {MPEG2_PAT_ERROR_PID_USE, NULL, "pid usage conflict"},
    {0, NULL, NULL}
};

static RetCodeId    retCodeId;

Mpeg2Pat
mpeg2PatNew(void)
{
    Mpeg2Pat            mpeg2Pat;

    if (retCodeId == 0) {
	retCodeId = retCodeRegisterWithTable(MPEG2PAT_CLASSNAME,
					     mpeg2PatErrorTable);
    }
    mpeg2Pat = NEW_ZEROED(struct _Mpeg2Pat, 1);

    mpeg2Pat->pat[MPEG2_PAT_NEXT].psiExtension.currentNextIndicator
      = MPEG2_PAT_NEXT;
    mpeg2Pat->pat[MPEG2_PAT_CURRENT].psiExtension.currentNextIndicator
      = MPEG2_PAT_CURRENT;

    mpeg2Pat->po.maxChunk = mpeg2PatMaxChunk;
    mpeg2Pat->po.recognize = NULL;
    mpeg2Pat->po.parse = mpeg2PatParse;
    mpeg2Pat->po.recover = mpeg2PatRecover;
    mpeg2Pat->po.instp = mpeg2Pat;

    return mpeg2Pat;
}

void
mpeg2PatSetPsiParsers(Mpeg2Pat mpeg2Pat, MmpParserObject *netPop,
		      MmpParserObject *psiPop)
{
    mpeg2PatRecover(mpeg2Pat);
    mpeg2Pat->netPop = netPop;
    mpeg2Pat->psiPop = psiPop;
}


MmpParserObject    *
mpeg2PatParserObject(Mpeg2Pat mpeg2Pat)
{
    return &mpeg2Pat->po;
}

void
mpeg2PatSetCallBack(Mpeg2Pat mpeg2Pat, Mpeg2PatCallBack callBack, void *token)
{
    mpeg2Pat->callBack = callBack;
    mpeg2Pat->token = token;
}

Mpeg2PatStatus
mpeg2PatStatus(Mpeg2Pat mpeg2Pat)
{
    Mpeg2PatStatus      patStatus;

    patStatus.pat[0] = mpeg2Pat->pat[0];
    patStatus.pat[1] = mpeg2Pat->pat[1];
    return patStatus;
}

void
mpeg2PatFree(Mpeg2Pat mpeg2Pat)
{
    mpeg2PatRecover(mpeg2Pat);
    free(mpeg2Pat);
}

/* ARGSUSED */
static size_t
mpeg2PatMaxChunk(void *instp)
{
    return MPEG2_PAT_MAX_CHUNK;
}

static RetCode
mpeg2PatParse(void *instp, MmpContextObject *cop, Pipe pipe)
{
    Mpeg2Pat            mpeg2Pat = (Mpeg2Pat) instp;
    Mpeg2PatInfo        info;
    Mpeg2PatInfo       *infop = &info;
    Mpeg2PatTable      *patp;
    PipePosition        patEnd;
    RetCode             retCode;

    mpeg2Pat->isDirty = TRUE;
    (void) memset(infop, 0, sizeof(*infop));

    infop->position = pipePosition(pipe);
    patEnd = pipeRelativePosition(pipe);
    infop->psiHeader = *PIPE_GET(pipe, Mpeg2PsiHeader);
    if (!infop->psiHeader.sectionSyntaxIndicator) {
	retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_SSI);
	goto error;
    }
    infop->psiExtension = *PIPE_GET(pipe, Mpeg2PsiExtension);

    if (infop->psiExtension.sectionNumber
	    > infop->psiExtension.lastSectionNumber) {
	retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_SN);
	goto error;
    }
    /*
     * PAT's can only come on pid 0
     */
    if (MMP_CONTEXT_PIPETOPID(cop, pipe) != MPEG2_PAT_PID) {
	retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_PID);
	goto error;
    }
    patEnd += MPEG2_PSI_HEADER_SECTION_LENGTH(&infop->psiHeader)
      + sizeof(Mpeg2PsiHeader);

    /*
     * If version number doesn't match current contents of pat, invalidate
     * that pat.  Then check if "next" pat vn matches, if so, promote it to
     * the current pat.
     */
    patp = &mpeg2Pat->pat[infop->psiExtension.currentNextIndicator];
    if (patp->isValid
	    && infop->psiExtension.versionNumber
	    != patp->psiExtension.versionNumber) {
	mpeg2PatDeactivate(patp);
    }
    if (!patp->isValid) {
	patp->psiExtension = infop->psiExtension;
	patp->isValid = TRUE;
    } else if (infop->psiExtension.lastSectionNumber
	       != patp->psiExtension.lastSectionNumber) {
	retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_LSN);
	goto error;
    }
    if (infop->psiExtension.currentNextIndicator == MPEG2_PAT_CURRENT
	    && mpeg2Pat->pat[MPEG2_PAT_NEXT].psiExtension.versionNumber
	    == infop->psiExtension.versionNumber
	    && mpeg2Pat->pat[MPEG2_PAT_NEXT].isValid) {
	if ((retCode = mpeg2PatPromote(mpeg2Pat, cop))
		!= RETCODE_SUCCESS) {
	    goto error;
	}
    }
    /*
     * Now, load new pat section and validate crc
     */
    infop->patSection.nPatEntries = 0;
    while (pipeRelativePosition(pipe) + 4 < patEnd) {
	if (infop->patSection.nPatEntries
		>= MPEG2_PAT_MAX_ENTRIES_PER_SECTION) {
	    return RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_SL);
	}
	infop->patSection.patEntries[infop->patSection.nPatEntries++]
	  = *PIPE_GET(pipe, Mpeg2PatEntry);
    }
    if (patEnd - pipeRelativePosition(pipe) != 4) {
	retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_LEN);
	goto error;
    }
    /*
     * FIXME: Do this the normal way with 4 bytes?
     */
    infop->crc = pipeGetBits(pipe, 32);
    if (pipeCrcGet(pipe) != 0) {
	retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_CRC);
	goto error;
    }
    if (mpeg2Pat->callBack != NULL) {
	retCode = (*mpeg2Pat->callBack) (mpeg2Pat->token, infop,
					 RETCODE_SUCCESS);
	if (retCode != RETCODE_SUCCESS) {
	    return retCode;
	}
    }
    return mpeg2PatActivate(mpeg2Pat, cop, patp,
		      infop->psiExtension.sectionNumber, &infop->patSection);

error:
    if (mpeg2Pat->callBack != NULL) {
	(void) (*mpeg2Pat->callBack) (mpeg2Pat->token, infop, retCode);
    }
    return retCode;
}

static void
mpeg2PatRecover(void *instp)
{
    Mpeg2Pat            mpeg2Pat = (Mpeg2Pat) instp;

    if (! mpeg2Pat->isDirty) {
	return;
    }
    mpeg2Pat->isDirty = FALSE;
    mpeg2PatDeactivate(&mpeg2Pat->pat[MPEG2_PAT_CURRENT]);
    mpeg2PatDeactivate(&mpeg2Pat->pat[MPEG2_PAT_NEXT]);

    MMP_PARSER_RECOVER(mpeg2Pat->netPop);
    MMP_PARSER_RECOVER(mpeg2Pat->psiPop);
}

static RetCode
mpeg2PatActivate(Mpeg2Pat mpeg2Pat, MmpContextObject *cop, Mpeg2PatTable *patp,
		 unsigned sectionNumber, Mpeg2PatSection *psp)
{
    RetCode             retCode = RETCODE_SUCCESS;
    Mpeg2PatSection    *curPsp = patp->patSectionsp[sectionNumber];
    unsigned            pex;

    if (curPsp == NULL) {
	curPsp = DUP(Mpeg2PatSection, psp);
	patp->patSectionsp[sectionNumber] = curPsp;
	if (patp->psiExtension.currentNextIndicator == MPEG2_PAT_CURRENT) {
	    for (pex = 0; pex < curPsp->nPatEntries; pex++) {
	        Mpeg2PatEntry      *pep = &curPsp->patEntries[pex];
		unsigned            pn = MPEG2_PAT_ENTRY_PROGRAM_NUMBER(pep);
		unsigned            pid = MPEG2_PAT_ENTRY_PROGRAM_MAP_PID(pep);
		Pipe                pidPipe;
		MmpParserObject    *pop;

		switch (pn) {
		case MPEG2_PAT_PN_NETWORK_INFORMATION:
		    pop = mpeg2Pat->netPop;
		    break;
		default:
		    pop = mpeg2Pat->psiPop;
		    break;
		}

		curPsp->cops[pex] = cop;
		if ((pidPipe = MMP_CONTEXT_PIDTOPIPE(cop, pid)) == NULL) {
		    pidPipe = MMP_PARSER_NEWPIPE(pop, cop);
		    retCode = MMP_CONTEXT_ADDPIPE(cop, pid, pidPipe);
		    /*
		     * ADDPIPE can't fail, just checked...
		     */
		    ASSERT(retCode == RETCODE_SUCCESS);
		} else if (! MMP_PARSER_ISOWNPIPE(pop, pidPipe)) {
		    retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_PID_USE);
		    goto done;
		}
	    }
	}
    } else {
	if (curPsp->nPatEntries != psp->nPatEntries) {
	    retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_MISMATCH);
	    goto done;
	}
	for (pex = 0; pex < psp->nPatEntries; pex++) {
	    Mpeg2PatEntry      *pep = &psp->patEntries[pex];
	    Mpeg2PatEntry      *curPep = &curPsp->patEntries[pex];
	    if (MPEG2_PAT_ENTRY_PROGRAM_NUMBER(pep)
		    != MPEG2_PAT_ENTRY_PROGRAM_NUMBER(curPep)
		    || MPEG2_PAT_ENTRY_PROGRAM_MAP_PID(pep)
		    != MPEG2_PAT_ENTRY_PROGRAM_MAP_PID(curPep)
		    || cop != curPsp->cops[pex]) {
		retCode = RETCODE_CONS(retCodeId, MPEG2_PAT_ERROR_MISMATCH);
		goto done;
	    }
	}
    }
done:
    return retCode;
}

static RetCode
mpeg2PatPromote(Mpeg2Pat mpeg2Pat, MmpContextObject *cop)
{
    RetCode             retCode = RETCODE_SUCCESS;
    Mpeg2PatTable      *nextPatp = &mpeg2Pat->pat[MPEG2_PAT_NEXT];
    Mpeg2PatTable      *curPatp = &mpeg2Pat->pat[MPEG2_PAT_CURRENT];
    unsigned            sn;

    ASSERT(nextPatp->psiExtension.versionNumber
	   == curPatp->psiExtension.versionNumber);

    for (sn = 0; sn <= nextPatp->psiExtension.lastSectionNumber; sn++) {
	Mpeg2PatSection    *psp = nextPatp->patSectionsp[sn];

	if (psp == NULL) {
	    continue;
	}
	if ((retCode = mpeg2PatActivate(mpeg2Pat, cop, curPatp, sn, psp))
		!= RETCODE_SUCCESS) {
	    return retCode;
	}
	free(psp);
	nextPatp->patSectionsp[sn] = NULL;
    }
    nextPatp->isValid = FALSE;
    return retCode;
}

static void
mpeg2PatDeactivate(Mpeg2PatTable *patp)
{
    unsigned            sn;

    if (patp->isValid) {
	for (sn = 0; sn <= patp->psiExtension.lastSectionNumber; sn++) {
	    Mpeg2PatSection    *psp = patp->patSectionsp[sn];

	    if (psp == NULL) {
		continue;
	    }
	    if (patp->psiExtension.currentNextIndicator == MPEG2_PAT_CURRENT) {
                unsigned            pex;
	        for (pex = 0; pex < psp->nPatEntries; pex++) {
	            Mpeg2PatEntry      *pep = &psp->patEntries[pex];
		    (void) MMP_CONTEXT_DELETEPIPE(psp->cops[pex],
				      MPEG2_PAT_ENTRY_PROGRAM_MAP_PID(pep));
		}
	    }
	    free(psp);
	    patp->patSectionsp[sn] = NULL;
	}
	patp->isValid = FALSE;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -