📄 dr_prefetch_dvd.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_dvd.cpp
*
* Prefetch class for the DR
*
* $Id: dr_prefetch_dvd.cpp,v 1.19 2007/01/26 20:47:06 rbehe Exp $
*/
#include <stdlib.h>
#include "vdvd_types.h"
#include "utility.h"
#include "loader_app.h"
#include "dr_types.h"
#include "dr_prefetch_dvd.h"
#include "css.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#define DEBUG_DR_PREFETCH DBG_ERROR
#define DBG_ON(x) (DEBUG_DR_PREFETCH >= x)
/* DVD Specific Defines */
#define MAX_SECTORS_PER_READ 16
#define PCI_PACKET_OFFSET 38
#define VOBU_SE_E_PTM_OFFSET 27
#define VOBU_S_PTM_OFFSET 19
#define PREU_FLAG 0x8000
#define ILVU_FLAG 0x4000
#define UNIT_START_FLAG 0x2000
#define UNIT_END_FLAG 0x1000
inline DR_ERROR drParseDSI(dsipkt_struct &dsi_packet, UCHAR *buf);
inline ULONG drGetVobuEndAddr(dsipkt_struct *dsi_packet, ULONG read_until_ref, ULONG ulNavPackLBN);
/**********************************************
*
* Implementations for DRPrefetch_DVD Derived Class
*
**********************************************/
/**
* Private function used to send a timing 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_DVD::drSendVobuInfo(ULONG ulVobuCC, BOOLEAN fIsVobuStill)
{
DROUTPUTMESSAGE streamMessage;
cPayload *pStreamPayload = NULL;
INFOPAYLOAD *infoPayload;
/* 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_VOBUINFO;
/* set the data */
infoPayload->vobu.ulVobuCC = ulVobuCC;
infoPayload->vobu.fIsVobuStill = fIsVobuStill;
/* send navpack id with the message */
streamMessage.ulVobuCC = m_ulVobuCC;
streamMessage.fIsVobuStill = fIsVobuStill;
/* transfer the payload to the PE */
drSendStream(streamMessage, pStreamPayload);
/* delete the payload */
delete pStreamPayload;
pStreamPayload = NULL;
return (DR_SUCCESS);
}
/**
* 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_DVD::dataRetrieve(PLAYCMD playcmd)
{
BOOLEAN fReadOk = FALSE;
ULONG ulCurrentSector;
ULONG ulVobuEndAddr;
ULONG ulSectorCount;
ULONG ulNumSectors;
ULONG ulLoopBuf;
ULONG ulSectorsToRead;
ULONG ulSectorsLeft;
BYTE *pDataPtr = NULL;
BOOLEAN fSeqEndDetected = FALSE;
ULONG ulNextSector;
DROUTPUTMESSAGE streamMessage;
cPayload *pStreamPayload = NULL;
BOOLEAN fSendTimeInfo = TRUE;
LOADER_ERR ldrStatus;
/* send beginning of stream for every play request */
streamMessage.BegOfStream = TRUE;
OS_SemGive(m_semPlayQueueEnabled);
if (m_encryption_type == CSS)
{
drGetTitleKey(playcmd.dvd.ulStart);
}
/* check our queue type. If it is an abort the new data should always be
* considered discontinuous from the previous */
if ( (playcmd.dvd.queueType == DR_QUEUE_ABORT) || (playcmd.dvd.queueType == DR_QUEUE_NONSEAMLESS) )
{
DBGPRINT(DBG_ON(DBG_TRACE), ("discontinuity at beginning\n"));
streamMessage.DiscontinuityAtBeginning = TRUE;
}
if (playcmd.dvd.playType == DR_TYPE_LBN)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("DR_TYPE_LBN\n"));
/* for LBN type playback we just play from the first to last sector with
* no DVD navigation (ie. no nav pack parsing required) */
m_ulNavPackLBN = 0;
ulCurrentSector = playcmd.dvd.ulStart;
ulVobuEndAddr = playcmd.dvd.ulEnd;
}
else
{
DBGPRINT(DBG_ON(DBG_TRACE), ("skip_vobu=%d, read_until_ref=%d\n", m_skip_vobu, m_read_until_ref));
if ( (m_skip_vobu >= DR_BWDI_PREV) || (playcmd.dvd.queueType == DR_QUEUE_NONSEAMLESS) )
{
/* jump to last VOBU in cell */
m_ulNavPackLBN = playcmd.dvd.ulBegin;
ulCurrentSector = playcmd.dvd.ulBegin;
ulVobuEndAddr = playcmd.dvd.ulEnd;
}
else
{
m_ulNavPackLBN = playcmd.dvd.ulStart;
ulCurrentSector = playcmd.dvd.ulStart;
ulVobuEndAddr = playcmd.dvd.ulEnd;
}
}
DBGPRINT(DBG_ON(DBG_TRACE), ("DR_PLAY -- firstLBN=%x, lastLBN=%x, trickLBN=%x, NavPckLBN=%x\n",
playcmd.dvd.ulStart, playcmd.dvd.ulEnd, playcmd.dvd.ulBegin, m_ulNavPackLBN));
do /* while not up to the last sector */
{
/* release old payload */
if (pStreamPayload != NULL)
{
delete pStreamPayload;
pStreamPayload = NULL;
}
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;
}
/* how many sector remain? */
ulSectorCount = (playcmd.dvd.ulEnd - ulCurrentSector) + 1;
/* how many sectors can fit in the buffer */
ulNumSectors = (ULONG)((pStreamPayload->get_max_size()) / DVD_SECTOR_SIZE);
/* make sure there are is at least 32K left to read */
if (ulNumSectors > ulSectorCount)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("DRDataProc() -- ulSectorCount=%d, ulNumSectors=%d\n", ulSectorCount, ulNumSectors));
ulNumSectors = ulSectorCount;
}
/* Read enough data to fill the buffer */
for (ulLoopBuf=0; ulLoopBuf < ulNumSectors; )
{
if (playcmd.dvd.playType == DR_TYPE_LBN)
{
ulSectorsToRead = ulNumSectors;
}
else
{
ulSectorsLeft = ulNumSectors - ulLoopBuf;
ulSectorsToRead = (ulSectorsLeft < MAX_SECTORS_PER_READ) ? ulSectorsLeft : MAX_SECTORS_PER_READ;
}
/* Grab the address we are about to read data into...
* we need this so we can keep track of where we are in the buffer for nav pack parsing. */
pDataPtr = (BYTE*)pStreamPayload->get_wr_ptr();
ldrStatus = LoaderSectorReadAV(m_loader, ulCurrentSector, pDataPtr, ulSectorsToRead);
if (ldrStatus == LOADER_SUCCESS)
{
/* check that the read begins with good data (program stream start code) */
if (MAKE_DWORD(pDataPtr) != 0x000001ba)
{
DbgPrint(("LoaderFileRead: bad data read from disk.\n"));
ldrStatus = LOADER_FAILURE;
}
}
if (ldrStatus == LOADER_SUCCESS)
{
fReadOk = TRUE;
/* Parse the DSI info */
if (playcmd.dvd.playType != DR_TYPE_LBN)
{
int i;
OS_SemTake(m_semAngleChg, OS_WAIT_FOREVER);
for (i=0; i<(int)ulSectorsToRead; i++)
{
/* DSI starts 1024 bytes later if this is a nav pack */
if (drParseDSI(m_dsi_packet, ((BYTE *)(KSEG1(pDataPtr)))+1024) == DR_SUCCESS )
{
/* Set cell position information of this vobu */
m_ulCellPosition = (m_dsi_packet.dsi_gi.vobu_vob_idn << 16);
m_ulCellPosition |= m_dsi_packet.dsi_gi.vobu_c_idn;
/* remember which sector this came from */
m_ulNavPackLBN = ulCurrentSector;
/* determine the VOBU end address */
ulVobuEndAddr = drGetVobuEndAddr(&m_dsi_packet, m_read_until_ref, m_ulNavPackLBN);
/* determine if VOBU contains a sequence end code by looking at the
* pci vobu_se_e_ptm value. A non-zero value indicates seq end exists */
fSeqEndDetected = (MAKE_DWORD(&( ((BYTE *)(KSEG1(pDataPtr)))[PCI_PACKET_OFFSET + VOBU_SE_E_PTM_OFFSET])) != 0);
/* send cell timing Info */
if (fSendTimeInfo == TRUE)
{
TIME45k startTime;
TIME45k stopTime;
/* Use the min of navpack scr from the DSI or the VOBU_S_PTM
* if it's less than the navpack scr. This "should" never happen, but it does
* on some "bad" content. */
startTime = MAKE_DWORD(&( ((BYTE *)(KSEG1(pDataPtr)))[PCI_PACKET_OFFSET + VOBU_S_PTM_OFFSET]))/2;
startTime = MIN(startTime, m_dsi_packet.dsi_gi.nv_pck_scr);
if (playcmd.dvd.fIsLastCell == FALSE)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("\n\nNOT LAST CELL\n\n"));
stopTime = 0xffffffff;
}
else
{
DBGPRINT(DBG_ON(DBG_TRACE), ("\n\nLAST CELL\n\n"));
stopTime = m_dsi_packet.sml_pbi.vob_v_e_ptm/2;
/* validate stop time */
if (stopTime < startTime)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("\n\nstopTime INVALID!\n\n"));
stopTime = 0xffffffff;
}
}
DBGPRINT(DBG_ON(DBG_TRACE), ("DR:dataRetrieve() -- startTime=0x%lx, stopTime=0x%lx\n",
startTime, stopTime));
if (streamMessage.DiscontinuityAtBeginning == TRUE)
{
drSendTimingInfo(1, VDVD_CONNECTION_1, startTime, stopTime, NULL);
}
else
{
drSendTimingInfo(1, VDVD_CONNECTION_5, startTime, stopTime, NULL);
}
fSendTimeInfo = FALSE;
}
/* send vobu still and continuity count */
drSendVobuInfo(m_ulVobuCC++, playcmd.dvd.fIsVobuStill);
}
pDataPtr += DVD_SECTOR_SIZE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -