📄 dr_prefetch_cdda.cpp
字号:
/*****************************************************************************
******************************************************************************
** **
** Copyright (c) 2005 Videon Central, Inc. **
** All rights reserved. **
** **
** The computer program contained herein contains proprietary information **
** which is the property of Videon Central, Inc. The program may be used **
** and/or copied only with the written permission of Videon Central, Inc. **
** or in accordance with the terms and conditions stipulated in the **
** agreement/contract under which the programs have been supplied. **
** **
******************************************************************************
*****************************************************************************/
/**
* @file dr_prefetch_cdda.cpp
*
* Prefetch class for the DR
*
* $Id: dr_prefetch_cdda.cpp,v 1.8 2007/01/05 02:02:54 rbehe Exp $
*/
#include <stdlib.h>
#include "vdvd_types.h"
#include "loader_app.h"
#include "dr_types.h"
#include "dr_prefetch_cdda.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#define DEBUG_DR_PREFETCH DBG_ERROR
#define DBG_ON(x) (DEBUG_DR_PREFETCH >= x)
/* CD Specific Defines */
#define CD_TRICK_NUM_SECTORS 16
#define CD_SECTORS_PER_PAYLOAD 2
/**********************************************
*
* Implementations for DRPrefetch_CDDA Derived Class
*
**********************************************/
/**
* Private function used to send a QData packet to the PE.
*
* @param ulVobuCC - The Vobu "count".
* @param fIsVobuStill - Flag to indicate that the player should pause at the end of this vobu.
*
* @retval DR_ERROR
*/
DR_ERROR DRPrefetch_CDDA::drSendQData(void)
{
DR_ERROR drStatus = DR_SUCCESS;
DROUTPUTMESSAGE streamMessage;
cPayload *pStreamPayload = NULL;
INFOPAYLOAD *infoPayload = NULL;
BYTE *pSubChannData = NULL;
/* it's an info payload */
streamMessage.fInfoPayload = TRUE;
/* Get a buffer from the stream */
pStreamPayload = drGetPayload();
if (pStreamPayload == NULL)
{
return (DR_FAILURE);
}
/* get the payload's write pointer */
infoPayload = (INFOPAYLOAD*)pStreamPayload->get_base_ptr();
/* set the type */
infoPayload->bType = INFOTYPE_CDDA_QDATA;
pSubChannData = (BYTE *)&(infoPayload->data_packet.data)[0];
if (LoaderReadSubChannel(m_loader, TRUE, TRUE, 0x01, 0x00, pSubChannData, 12) != LOADER_SUCCESS)
{
DbgPrint(("\n\nDR: LoaderReadSubChannel Error\n"));
drStatus = DR_FAILURE;
goto errout;
}
/* set the data */
infoPayload->data_packet.size = 12;
infoPayload->data_packet.offset = 0;
/* transfer the payload to the PE */
drSendStream(streamMessage, pStreamPayload);
errout:
/* delete the payload */
delete pStreamPayload;
pStreamPayload = NULL;
return (drStatus);
}
/**
* dataRetrieve - retrieve data from the disk and put into the prefetch thread
*
* @param playcmd - contains details for the data retrieval
*
* @retval none
*
* @remarks none.
*/
DR_ERROR DRPrefetch_CDDA::dataRetrieve(PLAYCMD playcmd)
{
BOOLEAN fDataOk = FALSE;
BOOLEAN fReadErr = FALSE;
ULONG ulCurrentSector = 0;
ULONG ulSectorSize = 1;
ULONG ulWriteSize = 0;
ULONG ulSectorCount = 0;
ULONG ulNumSectors = 0;
ULONG ulSectorsToRead = 0;
LOADER_CD_DATA_SELECT dataselect = LOADER_CDDS_NONE;
cPayload *pStreamPayload = NULL;
DROUTPUTMESSAGE streamMessage;
ULONG ulHighBound, ulLowBound;
OS_SemGive(m_semPlayQueueEnabled);
if (playcmd.cd.playType == DR_TYPE_VOB)
{
return (DR_INVALID_PARAM);
}
/* send beginning of stream for every play request */
streamMessage.BegOfStream = TRUE;
/* check our queue type. If it is an abort the new data should always be
* considered discontinuous from the previous */
if ( (playcmd.cd.queueType == DR_QUEUE_ABORT) || (playcmd.cd.queueType == DR_QUEUE_NONSEAMLESS) )
{
DBGPRINT(DBG_ON(DBG_TRACE), ("discontinuity at beginning\n"));
streamMessage.DiscontinuityAtBeginning = TRUE;
}
if (playcmd.cd.playType == DR_TYPE_MSF)
{
/* translate addresses to lbn */
playcmd.cd.ulStart = MSFUL_TO_LBA(playcmd.cd.ulStart);
playcmd.cd.ulEnd = MSFUL_TO_LBA(playcmd.cd.ulEnd);
}
/*
* from here on, all addresses are in lbn
*/
/* start at the beginning */
ulCurrentSector = playcmd.cd.ulStart - ((playcmd.cd.sSpeed < 0) ? CD_TRICK_NUM_SECTORS : 0);
switch(playcmd.cd.sectorType)
{
case DR_CD_SECTOR_CDDA:
ulSectorSize = CDDA_SECTOR_SIZE;
dataselect = LOADER_CDDS_USER;
break;
default:
DbgPrint(("Sector Type doesn't exist for CDDA playback\n"));
return(DR_FAILURE);
break;
}
DBGPRINT(DBG_ON(DBG_TRACE), ("DR_PLAY -- firstLBN=%x, lastLBN=%x, startLBN=%x\n", playcmd.cd.ulStart, playcmd.cd.ulEnd, ulCurrentSector));
/* determine edge conditions of the read */
ulLowBound = (playcmd.cd.sSpeed > 0) ? playcmd.cd.ulStart : playcmd.cd.ulEnd;
ulHighBound = (playcmd.cd.sSpeed > 0) ? playcmd.cd.ulEnd : playcmd.cd.ulStart;
/* while not up to the last sector */
do
{
/* release old payload */
if (pStreamPayload != NULL)
{
delete pStreamPayload;
pStreamPayload = NULL;
}
/* if we should stop, then stop */
if (m_fAbort == TRUE)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("DRDataProc() -- flush/abort\n"));
break;
}
/* Get a buffer from the stream */
pStreamPayload = drGetPayload();
if (pStreamPayload == NULL)
{
break;
}
if (playcmd.cd.sSpeed == 1)
{ /* normal forward play */
/* how many sectors remain? */
ulSectorCount = (playcmd.cd.ulEnd - ulCurrentSector) + 1;
/* how many sectors can fit in the buffer */
ulNumSectors = (ULONG)((pStreamPayload->get_max_size()) / ulSectorSize);
/* Use the defined number of sectors only if it fits within the payload */
if (CD_SECTORS_PER_PAYLOAD <= ulNumSectors)
{
ulNumSectors = CD_SECTORS_PER_PAYLOAD;
}
/* if we're at the end, only read what's left */
if (ulNumSectors > ulSectorCount)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("DRDataProc() -- ulSectorCount=%d, ulNumSectors=%d\n", ulSectorCount, ulNumSectors));
ulNumSectors = ulSectorCount;
}
}
else
{ /* trick play */
ulNumSectors = CD_TRICK_NUM_SECTORS;
}
/* set the user data to the starting location */
if (playcmd.cd.playType == DR_TYPE_MSF)
{
pStreamPayload->set_user_data(LBA_TO_MSF(ulCurrentSector));
}
else
{
pStreamPayload->set_user_data(ulCurrentSector);
}
/* if the previous run had a read error, use the same ulSectorsToRead value */
if (fReadErr == FALSE)
{
ulSectorsToRead = ulNumSectors;
}
fDataOk = TRUE;
fReadErr = FALSE;
/* do the read - loop until successful */
while (LoaderCDRead(m_loader, ulCurrentSector, ulSectorsToRead,
(LOADER_CD_SECTOR_TYPE)playcmd.cd.sectorType, dataselect,
(BYTE*)pStreamPayload->get_wr_ptr(),
(ULONG)(pStreamPayload->get_max_size())) != LOADER_SUCCESS)
{
/* ERROR RECOVERY */
DbgPrint(("\n\nDR: LoaderSectorRead Error, sector = %lx\n", (long)ulCurrentSector));
ulWriteSize = 0;
fReadErr = TRUE;
/* if an event callback is registered then send an error notification */
if (m_event != NULL)
{
m_event(m_pContext, DR_EVENT_ERROR, NULL);
}
if (ulSectorsToRead > 1)
{
ulSectorsToRead /= 2;
}
else
{
/* the sector at ulCurrentSector is unreadable */
fDataOk = FALSE;
ulSectorsToRead = 0;
/* leap ahead to look for a good sector */
ulCurrentSector += 150;
}
}
ulWriteSize = ulSectorsToRead * ulSectorSize;
ulCurrentSector += ulSectorsToRead;
/* for trick modes (in normal play this statement has no effect) */
ulCurrentSector += (CD_TRICK_NUM_SECTORS * (playcmd.cd.sSpeed-1) );
/* Update the write pointer */
if (TRUE == fDataOk)
{
pStreamPayload->add_data(ulWriteSize);
}
/* force the EndOfStream flag */
if ( (ulCurrentSector > ulHighBound) || /* playing fwd reached end of sectors */
(ulCurrentSector < ulLowBound ) ) /* playing rev reached beg of sectors */
{
streamMessage.EndOfStream = TRUE;
}
/* Send the Q-data for the last sector that was read from the loader */
drSendQData();
/* transfer the payload to the PE */
drSendStream(streamMessage, pStreamPayload);
delete pStreamPayload;
pStreamPayload = NULL;
/* reset flags */
streamMessage.BegOfStream = FALSE;
streamMessage.SequenceEnd = FALSE;
streamMessage.EndOfStream = FALSE;
streamMessage.DiscontinuityAtBeginning = FALSE;
} while ( (ulCurrentSector <= ulHighBound) && (ulCurrentSector >= ulLowBound) );
return(DR_SUCCESS);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -