2012-11-01 15:19:01 +00:00
// Copyright (c) 2012- PPSSPP Project.
// 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
2012-11-04 22:01:49 +00:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 15:19:01 +00:00
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2012-11-12 19:53:16 +00:00
2014-01-14 18:31:09 +00:00
// This code is part shamelessly "inspired" from JPSCP.
2012-11-13 17:05:26 +00:00
# include <map>
2013-09-17 04:48:14 +00:00
# include <algorithm>
2012-11-12 19:53:16 +00:00
2012-11-01 15:19:01 +00:00
# include "sceMpeg.h"
2012-11-13 17:05:26 +00:00
# include "sceKernelThread.h"
2012-11-01 15:19:01 +00:00
# include "HLE.h"
2012-11-12 19:53:16 +00:00
# include "../HW/MediaEngine.h"
2013-06-01 21:53:07 +00:00
# include "Core/Config.h"
# include "Core/Reporting.h"
2013-06-08 11:50:36 +00:00
# include "GPU/GPUInterface.h"
# include "GPU/GPUState.h"
2012-11-12 19:53:16 +00:00
// MPEG AVC elementary stream.
static const int MPEG_AVC_ES_SIZE = 2048 ; // MPEG packet size.
2013-01-08 02:03:48 +00:00
2012-11-12 19:53:16 +00:00
// MPEG ATRAC elementary stream.
static const int MPEG_ATRAC_ES_SIZE = 2112 ;
static const int MPEG_ATRAC_ES_OUTPUT_SIZE = 8192 ;
2013-01-08 02:03:48 +00:00
2012-11-12 19:53:16 +00:00
// MPEG PCM elementary stream.
static const int MPEG_PCM_ES_SIZE = 320 ;
static const int MPEG_PCM_ES_OUTPUT_SIZE = 320 ;
2013-01-08 02:03:48 +00:00
// MPEG Userdata elementary stream.
static const int MPEG_DATA_ES_SIZE = 0xA0000 ;
static const int MPEG_DATA_ES_OUTPUT_SIZE = 0xA0000 ;
2014-02-01 15:56:34 +00:00
static const int MPEG_DATA_ES_BUFFERS = 2 ;
2013-01-08 02:03:48 +00:00
2012-11-12 19:53:16 +00:00
// MPEG analysis results.
static const int MPEG_VERSION_0012 = 0 ;
static const int MPEG_VERSION_0013 = 1 ;
static const int MPEG_VERSION_0014 = 2 ;
static const int MPEG_VERSION_0015 = 3 ;
2013-01-08 02:03:48 +00:00
2012-11-12 19:53:16 +00:00
// MPEG streams.
static const int MPEG_AVC_STREAM = 0 ;
static const int MPEG_ATRAC_STREAM = 1 ;
static const int MPEG_PCM_STREAM = 2 ;
static const int MPEG_DATA_STREAM = 3 ; // Arbitrary user defined type. Can represent audio or video.
static const int MPEG_AUDIO_STREAM = 15 ;
static const int MPEG_AU_MODE_DECODE = 0 ;
static const int MPEG_AU_MODE_SKIP = 1 ;
2013-04-06 03:58:35 +00:00
static const u32 MPEG_MEMSIZE = 0x10000 ; // 64k.
2012-11-12 19:53:16 +00:00
static const int MPEG_AVC_DECODE_SUCCESS = 1 ; // Internal value.
2013-04-21 05:38:56 +00:00
static const int atracDecodeDelayMs = 3000 ;
static const int avcFirstDelayMs = 3600 ;
static const int avcDecodeDelayMs = 5400 ; // Varies between 4700 and 6000.
static const int avcEmptyDelayMs = 320 ;
static const int mpegDecodeErrorDelayMs = 100 ;
static const int mpegTimestampPerSecond = 90000 ; // How many MPEG Timestamp units in a second.
2013-06-01 17:29:59 +00:00
static const int videoTimestampStep = 3003 ; // Value based on pmfplayer (mpegTimestampPerSecond / 29.970 (fps)).
2013-04-21 05:38:56 +00:00
static const int audioTimestampStep = 4180 ; // For audio play at 44100 Hz (2048 samples / 44100 * mpegTimestampPerSecond == 4180)
static const int audioFirstTimestamp = 90000 ; // The first MPEG audio AU has always this timestamp
2014-02-01 15:56:34 +00:00
static const int maxAheadTimestamp = 40000 ;
2012-11-12 19:53:16 +00:00
static const s64 UNKNOWN_TIMESTAMP = - 1 ;
// At least 2048 bytes of MPEG data is provided when analysing the MPEG header
static const int MPEG_HEADER_BUFFER_MINIMUM_SIZE = 2048 ;
2012-11-13 17:05:26 +00:00
int getMaxAheadTimestamp ( const SceMpegRingBuffer & ringbuf ) {
2014-02-01 15:56:34 +00:00
return std : : max ( maxAheadTimestamp , 700 * ringbuf . packets ) ; // empiric value from JPCSP, thanks!
2012-11-13 17:05:26 +00:00
}
2012-11-12 19:53:16 +00:00
2013-07-01 17:26:31 +00:00
const u8 defaultMpegheader [ 2048 ] = { 0x50 , 0x53 , 0x4d , 0x46 , 0x30 , 0x30 , 0x31 , 0x35 , 0x00 , 0x00 , 0x08 , 0x00 , 0x00 ,
2013-07-01 17:04:19 +00:00
0x10 , 0xc8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x4e , 0x00 ,
0x00 , 0x00 , 0x01 , 0x5f , 0x90 , 0x00 , 0x00 , 0x00 , 0x0d , 0xbe , 0xca , 0x00 , 0x00 , 0x61 , 0xa8 , 0x00 , 0x01 , 0x5f ,
0x90 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x34 , 0x00 , 0x00 , 0x00 , 0x01 , 0x5f , 0x90 , 0x00 , 0x00 , 0x00 , 0x0d , 0xbe ,
0xca , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x22 , 0x00 , 0x02 , 0xe0 , 0x00 , 0x20 , 0xfb , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x1e , 0x11 , 0x00 , 0x00 , 0xbd , 0x00 , 0x20 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x02 , 0x02 } ;
2012-11-13 17:05:26 +00:00
// Internal structure
struct AvcContext {
int avcDetailFrameWidth ;
int avcDetailFrameHeight ;
int avcDecodeResult ;
int avcFrameStatus ;
} ;
2012-11-12 19:53:16 +00:00
2013-01-09 08:59:27 +00:00
struct StreamInfo {
2012-11-13 17:05:26 +00:00
int type ;
int num ;
2013-01-08 08:16:18 +00:00
int sid ;
2013-04-01 14:56:43 +00:00
bool needsReset ;
2012-11-13 17:05:26 +00:00
} ;
2012-11-12 19:53:16 +00:00
2012-12-29 11:19:13 +00:00
typedef std : : map < u32 , StreamInfo > StreamInfoMap ;
2012-11-13 17:05:26 +00:00
// Internal structure
2012-12-29 11:19:13 +00:00
struct MpegContext {
2013-07-01 17:26:31 +00:00
MpegContext ( ) : mediaengine ( NULL ) { memcpy ( mpegheader , defaultMpegheader , 2048 ) ; }
2013-02-04 16:24:32 +00:00
~ MpegContext ( ) {
if ( mediaengine ! = NULL ) {
delete mediaengine ;
}
}
2012-12-29 11:19:13 +00:00
void DoState ( PointerWrap & p ) {
2013-09-15 03:23:03 +00:00
auto s = p . Section ( " MpegContext " , 1 ) ;
if ( ! s )
return ;
2013-07-01 17:26:31 +00:00
p . DoArray ( mpegheader , 2048 ) ;
2012-12-29 11:19:13 +00:00
p . Do ( defaultFrameWidth ) ;
p . Do ( videoFrameCount ) ;
p . Do ( audioFrameCount ) ;
p . Do ( endOfAudioReached ) ;
p . Do ( endOfVideoReached ) ;
p . Do ( videoPixelMode ) ;
p . Do ( mpegMagic ) ;
p . Do ( mpegVersion ) ;
p . Do ( mpegRawVersion ) ;
p . Do ( mpegOffset ) ;
p . Do ( mpegStreamSize ) ;
p . Do ( mpegFirstTimestamp ) ;
p . Do ( mpegLastTimestamp ) ;
p . Do ( mpegFirstDate ) ;
p . Do ( mpegLastDate ) ;
p . Do ( mpegRingbufferAddr ) ;
2014-02-01 15:56:34 +00:00
p . DoArray ( esBuffers , MPEG_DATA_ES_BUFFERS ) ;
2012-12-29 11:19:13 +00:00
p . Do ( avc ) ;
p . Do ( avcRegistered ) ;
p . Do ( atracRegistered ) ;
p . Do ( pcmRegistered ) ;
2013-01-08 08:16:18 +00:00
p . Do ( dataRegistered ) ;
2013-01-08 09:04:51 +00:00
p . Do ( ignoreAtrac ) ;
p . Do ( ignorePcm ) ;
p . Do ( ignoreAvc ) ;
2012-12-29 11:19:13 +00:00
p . Do ( isAnalyzed ) ;
2013-02-04 16:24:32 +00:00
p . Do < u32 , StreamInfo > ( streamMap ) ;
2013-02-04 09:31:02 +00:00
p . DoClass ( mediaengine ) ;
2012-12-29 11:19:13 +00:00
}
2013-07-01 17:26:31 +00:00
u8 mpegheader [ 2048 ] ;
2012-11-13 17:05:26 +00:00
u32 defaultFrameWidth ;
int videoFrameCount ;
int audioFrameCount ;
bool endOfAudioReached ;
bool endOfVideoReached ;
int videoPixelMode ;
u32 mpegMagic ;
2013-01-20 02:31:04 +00:00
int mpegVersion ;
2012-11-13 17:05:26 +00:00
u32 mpegRawVersion ;
2012-12-24 18:04:05 +00:00
u32 mpegOffset ;
2012-11-13 17:05:26 +00:00
u32 mpegStreamSize ;
2013-06-09 20:21:36 +00:00
s64 mpegFirstTimestamp ;
s64 mpegLastTimestamp ;
2012-11-13 17:05:26 +00:00
u32 mpegFirstDate ;
u32 mpegLastDate ;
u32 mpegRingbufferAddr ;
2014-02-01 15:56:34 +00:00
bool esBuffers [ MPEG_DATA_ES_BUFFERS ] ;
2012-11-13 17:05:26 +00:00
AvcContext avc ;
bool avcRegistered ;
bool atracRegistered ;
bool pcmRegistered ;
2013-01-08 08:16:18 +00:00
bool dataRegistered ;
2012-11-13 17:05:26 +00:00
2013-01-08 09:04:51 +00:00
bool ignoreAtrac ;
bool ignorePcm ;
bool ignoreAvc ;
2012-11-13 17:05:26 +00:00
bool isAnalyzed ;
2012-12-29 07:29:24 +00:00
StreamInfoMap streamMap ;
2012-11-13 17:05:26 +00:00
MediaEngine * mediaengine ;
} ;
2012-11-12 19:53:16 +00:00
2013-06-07 08:10:25 +00:00
static bool isMpegInit ;
2012-12-29 07:29:24 +00:00
static u32 streamIdGen ;
2012-12-24 18:31:33 +00:00
static bool isCurrentMpegAnalyzed ;
2012-12-29 07:29:24 +00:00
static int actionPostPut ;
2012-12-24 18:31:33 +00:00
static std : : map < u32 , MpegContext * > mpegMap ;
static u32 lastMpegHandle = 0 ;
MpegContext * getMpegCtx ( u32 mpegAddr ) {
u32 mpeg = Memory : : Read_U32 ( mpegAddr ) ;
if ( mpegMap . find ( mpeg ) = = mpegMap . end ( ) )
return NULL ;
2014-01-12 15:29:49 +00:00
2012-12-24 18:31:33 +00:00
return mpegMap [ mpeg ] ;
2012-11-13 17:05:26 +00:00
}
2012-11-12 19:53:16 +00:00
2012-11-13 17:05:26 +00:00
u32 getMpegHandle ( u32 mpeg ) {
return Memory : : Read_U32 ( mpeg ) ;
2012-11-12 19:53:16 +00:00
}
2012-11-13 17:05:26 +00:00
static void InitRingbuffer ( SceMpegRingBuffer * buf , int packets , int data , int size , int callback_addr , int callback_args ) {
buf - > packets = packets ;
buf - > packetsRead = 0 ;
buf - > packetsWritten = 0 ;
2013-06-01 17:29:59 +00:00
buf - > packetsFree = 0 ;
2012-11-13 17:05:26 +00:00
buf - > packetSize = 2048 ;
buf - > data = data ;
buf - > callback_addr = callback_addr ;
buf - > callback_args = callback_args ;
buf - > dataUpperBound = data + packets * 2048 ;
2014-01-06 06:20:27 +00:00
buf - > semaID = 0 ;
2012-11-13 17:05:26 +00:00
buf - > mpeg = 0 ;
2014-01-08 08:07:25 +00:00
// TODO: This appears in tests, but may not be in all versions.
//buf->gp = __KernelGetModuleGP(__KernelGetCurThreadModuleId());
2014-01-06 06:20:27 +00:00
}
2012-11-13 17:05:26 +00:00
2012-11-12 19:53:16 +00:00
u32 convertTimestampToDate ( u32 ts ) {
return ts ; // TODO
}
2013-07-01 17:04:19 +00:00
void AnalyzeMpeg ( u8 * buffer , MpegContext * ctx ) {
2013-07-30 19:48:14 +00:00
ctx - > mpegMagic = * ( u32_le * ) buffer ;
ctx - > mpegRawVersion = * ( u32_le * ) ( buffer + PSMF_STREAM_VERSION_OFFSET ) ;
2012-11-13 17:05:26 +00:00
switch ( ctx - > mpegRawVersion ) {
2012-11-12 19:53:16 +00:00
case PSMF_VERSION_0012 :
2012-11-13 17:05:26 +00:00
ctx - > mpegVersion = MPEG_VERSION_0012 ;
2012-11-12 19:53:16 +00:00
break ;
case PSMF_VERSION_0013 :
2012-11-13 17:05:26 +00:00
ctx - > mpegVersion = MPEG_VERSION_0013 ;
2012-11-12 19:53:16 +00:00
break ;
case PSMF_VERSION_0014 :
2012-11-13 17:05:26 +00:00
ctx - > mpegVersion = MPEG_VERSION_0014 ;
2012-11-12 19:53:16 +00:00
break ;
case PSMF_VERSION_0015 :
2012-11-13 17:05:26 +00:00
ctx - > mpegVersion = MPEG_VERSION_0015 ;
2012-11-12 19:53:16 +00:00
break ;
default :
2012-11-13 17:05:26 +00:00
ctx - > mpegVersion = - 1 ;
2012-11-12 19:53:16 +00:00
break ;
}
2013-10-28 16:23:51 +00:00
ctx - > mpegOffset = bswap32 ( * ( u32_le * ) ( buffer + PSMF_STREAM_OFFSET_OFFSET ) ) ;
ctx - > mpegStreamSize = bswap32 ( * ( u32_le * ) ( buffer + PSMF_STREAM_SIZE_OFFSET ) ) ;
2013-07-01 17:04:19 +00:00
ctx - > mpegFirstTimestamp = getMpegTimeStamp ( buffer + PSMF_FIRST_TIMESTAMP_OFFSET ) ;
ctx - > mpegLastTimestamp = getMpegTimeStamp ( buffer + PSMF_LAST_TIMESTAMP_OFFSET ) ;
2012-11-13 17:05:26 +00:00
ctx - > mpegFirstDate = convertTimestampToDate ( ctx - > mpegFirstTimestamp ) ;
ctx - > mpegLastDate = convertTimestampToDate ( ctx - > mpegLastTimestamp ) ;
2013-07-01 17:04:19 +00:00
ctx - > avc . avcDetailFrameWidth = ( * ( u8 * ) ( buffer + 142 ) ) * 0x10 ;
ctx - > avc . avcDetailFrameHeight = ( * ( u8 * ) ( buffer + 143 ) ) * 0x10 ;
2014-01-25 13:29:37 +00:00
ctx - > avc . avcDecodeResult = MPEG_AVC_DECODE_SUCCESS ;
2012-11-13 17:05:26 +00:00
ctx - > avc . avcFrameStatus = 0 ;
ctx - > videoFrameCount = 0 ;
ctx - > audioFrameCount = 0 ;
ctx - > endOfAudioReached = false ;
ctx - > endOfVideoReached = false ;
2013-06-05 07:46:04 +00:00
if ( ctx - > mpegMagic ! = PSMF_MAGIC | | ctx - > mpegVersion < 0 | |
( ctx - > mpegOffset & 2047 ) ! = 0 | | ctx - > mpegOffset = = 0 ) {
// mpeg header is invalid!
return ;
}
2013-09-21 04:03:54 +00:00
if ( ctx - > mediaengine & & ( ctx - > mpegStreamSize > 0 ) & & ! ctx - > isAnalyzed ) {
// init mediaEngine
SceMpegRingBuffer ringbuffer = { 0 } ;
if ( ctx - > mpegRingbufferAddr ! = 0 ) {
Memory : : ReadStruct ( ctx - > mpegRingbufferAddr , & ringbuffer ) ;
} ;
ctx - > mediaengine - > loadStream ( buffer , ctx - > mpegOffset , ringbuffer . packets * ringbuffer . packetSize ) ;
ctx - > mediaengine - > setVideoDim ( ) ;
}
2012-11-12 19:53:16 +00:00
// When used with scePsmf, some applications attempt to use sceMpegQueryStreamOffset
// and sceMpegQueryStreamSize, which forces a packet overwrite in the Media Engine and in
// the MPEG ringbuffer.
// Mark the current MPEG as analyzed to filter this, and restore it at sceMpegFinish.
2012-11-13 17:05:26 +00:00
ctx - > isAnalyzed = true ;
2012-11-12 19:53:16 +00:00
2013-07-01 17:04:19 +00:00
// copy header struct to mpeg header.
2013-07-01 17:26:31 +00:00
memcpy ( ctx - > mpegheader , buffer , 2048 ) ;
2013-07-30 19:48:14 +00:00
* ( u32_le * ) ( ctx - > mpegheader + PSMF_STREAM_OFFSET_OFFSET ) = 0x80000 ;
2013-07-01 17:04:19 +00:00
2012-11-13 17:05:26 +00:00
INFO_LOG ( ME , " Stream offset: %d, Stream size: 0x%X " , ctx - > mpegOffset , ctx - > mpegStreamSize ) ;
2013-06-09 20:21:36 +00:00
INFO_LOG ( ME , " First timestamp: %lld, Last timestamp: %lld " , ctx - > mpegFirstTimestamp , ctx - > mpegLastTimestamp ) ;
2012-11-12 19:53:16 +00:00
}
2012-12-29 07:29:24 +00:00
class PostPutAction : public Action {
public :
PostPutAction ( ) { }
void setRingAddr ( u32 ringAddr ) { ringAddr_ = ringAddr ; }
static Action * Create ( ) { return new PostPutAction ; }
2013-09-15 03:23:03 +00:00
void DoState ( PointerWrap & p ) {
auto s = p . Section ( " PostPutAction " , 1 ) ;
if ( ! s )
return ;
p . Do ( ringAddr_ ) ;
}
2013-01-06 18:54:33 +00:00
void run ( MipsCall & call ) ;
2012-12-29 07:29:24 +00:00
private :
u32 ringAddr_ ;
} ;
2012-11-12 19:53:16 +00:00
2013-06-08 20:53:36 +00:00
void __MpegInit ( ) {
2012-12-29 07:29:24 +00:00
lastMpegHandle = 0 ;
2012-11-13 17:05:26 +00:00
streamIdGen = 1 ;
2012-12-24 18:31:33 +00:00
isCurrentMpegAnalyzed = false ;
2013-06-07 08:10:25 +00:00
isMpegInit = false ;
2012-12-29 07:29:24 +00:00
actionPostPut = __KernelRegisterActionType ( PostPutAction : : Create ) ;
2013-01-20 13:30:16 +00:00
# ifdef USING_FFMPEG
avcodec_register_all ( ) ;
av_register_all ( ) ;
# endif
2012-11-12 19:53:16 +00:00
}
2012-12-29 07:29:24 +00:00
void __MpegDoState ( PointerWrap & p ) {
2014-01-14 18:31:09 +00:00
auto s = p . Section ( " sceMpeg " , 1 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2012-12-29 07:29:24 +00:00
p . Do ( lastMpegHandle ) ;
p . Do ( streamIdGen ) ;
p . Do ( isCurrentMpegAnalyzed ) ;
2013-06-07 08:10:25 +00:00
p . Do ( isMpegInit ) ;
2012-12-29 07:29:24 +00:00
p . Do ( actionPostPut ) ;
__KernelRestoreActionType ( actionPostPut , PostPutAction : : Create ) ;
2013-02-04 09:31:02 +00:00
p . Do ( mpegMap ) ;
2012-12-29 07:29:24 +00:00
}
2012-11-12 19:53:16 +00:00
2012-11-13 17:05:26 +00:00
void __MpegShutdown ( ) {
2012-12-24 18:31:33 +00:00
std : : map < u32 , MpegContext * > : : iterator it , end ;
2012-12-29 07:29:24 +00:00
for ( it = mpegMap . begin ( ) , end = mpegMap . end ( ) ; it ! = end ; + + it ) {
2012-12-24 18:31:33 +00:00
delete it - > second ;
2012-12-24 19:16:47 +00:00
}
2012-12-24 18:31:33 +00:00
mpegMap . clear ( ) ;
2012-11-12 19:53:16 +00:00
}
2012-11-01 15:19:01 +00:00
2013-06-07 08:10:25 +00:00
u32 sceMpegInit ( ) {
if ( isMpegInit ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegInit(): already initialized " ) ;
2013-06-20 08:53:07 +00:00
// TODO: Need to properly hook module load/unload for this to work right.
//return ERROR_MPEG_ALREADY_INIT;
} else {
2013-09-07 20:02:55 +00:00
INFO_LOG ( ME , " sceMpegInit() " ) ;
2013-03-12 00:41:46 +00:00
}
2013-06-07 08:10:25 +00:00
isMpegInit = true ;
return hleDelayResult ( 0 , " mpeg init " , 750 ) ;
2012-11-12 19:53:16 +00:00
}
2014-01-06 06:20:27 +00:00
u32 __MpegRingbufferQueryMemSize ( int packets ) {
return packets * ( 104 + 2048 ) ;
}
u32 sceMpegRingbufferQueryMemSize ( int packets ) {
2014-02-01 15:56:34 +00:00
u32 size = __MpegRingbufferQueryMemSize ( packets ) ;
DEBUG_LOG ( ME , " %i = sceMpegRingbufferQueryMemSize(%i) " , size , packets ) ;
2014-02-01 16:43:40 +00:00
return size ;
2012-11-13 17:05:26 +00:00
}
2014-02-01 15:56:34 +00:00
2014-01-06 06:20:27 +00:00
u32 sceMpegRingbufferConstruct ( u32 ringbufferAddr , u32 numPackets , u32 data , u32 size , u32 callbackAddr , u32 callbackArg ) {
if ( ! Memory : : IsValidAddress ( ringbufferAddr ) ) {
ERROR_LOG_REPORT ( ME , " sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): bad ringbuffer, should crash " , ringbufferAddr , numPackets , data , size , callbackAddr , callbackArg ) ;
return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS ;
}
2014-02-01 15:56:34 +00:00
2014-01-06 06:20:27 +00:00
if ( ( int ) size < 0 ) {
ERROR_LOG_REPORT ( ME , " sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): invalid size " , ringbufferAddr , numPackets , data , size , callbackAddr , callbackArg ) ;
return ERROR_MPEG_NO_MEMORY ;
}
2014-02-01 15:56:34 +00:00
2014-01-06 06:20:27 +00:00
if ( __MpegRingbufferQueryMemSize ( numPackets ) > size ) {
if ( numPackets < 0x00100000 ) {
ERROR_LOG_REPORT ( ME , " sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer " , ringbufferAddr , numPackets , data , size , callbackAddr , callbackArg ) ;
return ERROR_MPEG_NO_MEMORY ;
} else {
// The PSP's firmware allows some cases here, due to a bug in its validation.
ERROR_LOG_REPORT ( ME , " sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer, bogus size " , ringbufferAddr , numPackets , data , size , callbackAddr , callbackArg ) ;
}
}
DEBUG_LOG ( ME , " sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x) " , ringbufferAddr , numPackets , data , size , callbackAddr , callbackArg ) ;
auto ring = PSPPointer < SceMpegRingBuffer > : : Create ( ringbufferAddr ) ;
InitRingbuffer ( ring , numPackets , data , size , callbackAddr , callbackArg ) ;
2012-11-13 17:05:26 +00:00
return 0 ;
}
2012-12-24 18:04:05 +00:00
u32 sceMpegCreate ( u32 mpegAddr , u32 dataPtr , u32 size , u32 ringbufferAddr , u32 frameWidth , u32 mode , u32 ddrTop )
2012-11-12 19:53:16 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( mpegAddr ) ) {
2014-01-28 13:56:49 +00:00
WARN_LOG ( ME , " sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i): invalid addresses " , mpegAddr , dataPtr , size , ringbufferAddr , frameWidth , mode , ddrTop ) ;
2014-01-03 19:47:59 +00:00
return - 1 ;
}
2012-11-12 19:53:16 +00:00
if ( size < MPEG_MEMSIZE ) {
2014-01-03 19:47:59 +00:00
WARN_LOG ( ME , " ERROR_MPEG_NO_MEMORY=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i) " , mpegAddr , dataPtr , size , ringbufferAddr , frameWidth , mode , ddrTop ) ;
2012-11-13 17:05:26 +00:00
return ERROR_MPEG_NO_MEMORY ;
2012-11-12 19:53:16 +00:00
}
SceMpegRingBuffer ringbuffer ;
2013-03-05 02:01:45 +00:00
if ( ringbufferAddr ! = 0 ) {
2013-06-01 17:29:59 +00:00
Memory : : ReadStruct ( ringbufferAddr , & ringbuffer ) ;
if ( ringbuffer . packetSize = = 0 ) {
ringbuffer . packetsFree = 0 ;
} else {
ringbuffer . packetsFree = ( ringbuffer . dataUpperBound - ringbuffer . data ) / ringbuffer . packetSize ;
}
ringbuffer . mpeg = mpegAddr ;
Memory : : WriteStruct ( ringbufferAddr , & ringbuffer ) ;
2013-03-05 02:01:45 +00:00
}
2012-11-12 19:53:16 +00:00
// Generate, and write mpeg handle into mpeg data, for some reason
2012-11-13 17:05:26 +00:00
int mpegHandle = dataPtr + 0x30 ;
Memory : : Write_U32 ( mpegHandle , mpegAddr ) ;
2012-11-12 19:53:16 +00:00
2014-02-01 15:56:34 +00:00
// Initialize fake mpeg struct.
2014-01-06 07:03:17 +00:00
Memory : : Memcpy ( mpegHandle , " LIBMPEG \0 " , 8 ) ;
Memory : : Memcpy ( mpegHandle + 8 , " 001 \0 " , 4 ) ;
2012-11-12 19:53:16 +00:00
Memory : : Write_U32 ( - 1 , mpegHandle + 12 ) ;
2014-02-01 15:56:34 +00:00
if ( ringbufferAddr ) {
2013-07-23 12:26:33 +00:00
Memory : : Write_U32 ( ringbufferAddr , mpegHandle + 16 ) ;
Memory : : Write_U32 ( ringbuffer . dataUpperBound , mpegHandle + 20 ) ;
}
2012-12-24 18:31:33 +00:00
MpegContext * ctx = new MpegContext ;
mpegMap [ mpegHandle ] = ctx ;
lastMpegHandle = mpegHandle ;
2012-11-13 17:05:26 +00:00
2014-02-01 15:56:34 +00:00
// Initialize mpeg values.
2012-11-13 17:05:26 +00:00
ctx - > mpegRingbufferAddr = ringbufferAddr ;
ctx - > videoFrameCount = 0 ;
ctx - > audioFrameCount = 0 ;
2014-02-01 15:56:34 +00:00
ctx - > videoPixelMode = GE_CMODE_32BIT_ABGR8888 ; // TODO: What's the actual default?
2012-11-13 17:05:26 +00:00
ctx - > avcRegistered = false ;
ctx - > atracRegistered = false ;
ctx - > pcmRegistered = false ;
2013-01-08 08:16:18 +00:00
ctx - > dataRegistered = false ;
2013-01-08 09:04:51 +00:00
ctx - > ignoreAtrac = false ;
ctx - > ignorePcm = false ;
ctx - > ignoreAvc = false ;
2012-11-13 17:05:26 +00:00
ctx - > defaultFrameWidth = frameWidth ;
2014-02-01 15:56:34 +00:00
for ( int i = 0 ; i < MPEG_DATA_ES_BUFFERS ; i + + ) {
2012-11-13 17:05:26 +00:00
ctx - > esBuffers [ i ] = false ;
}
// Detailed "analysis" is done later in Query* for some reason.
ctx - > isAnalyzed = false ;
ctx - > mediaengine = new MediaEngine ( ) ;
2012-12-24 19:07:11 +00:00
2014-01-03 19:47:59 +00:00
INFO_LOG ( ME , " %08x=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i) " , mpegHandle , mpegAddr , dataPtr , size , ringbufferAddr , frameWidth , mode , ddrTop ) ;
2013-06-07 08:13:09 +00:00
return hleDelayResult ( 0 , " mpeg create " , 29000 ) ;
2012-11-13 17:05:26 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegDelete ( u32 mpeg )
2012-11-13 17:05:26 +00:00
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegDelete(%08x): bad mpeg handle " , mpeg ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegDelete(%08x) " , mpeg ) ;
2012-12-24 18:04:05 +00:00
2012-12-24 18:31:33 +00:00
delete ctx ;
2013-01-05 20:53:39 +00:00
mpegMap . erase ( Memory : : Read_U32 ( mpeg ) ) ;
2012-11-13 17:05:26 +00:00
2012-12-17 17:48:32 +00:00
return 0 ;
2012-11-13 17:05:26 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegAvcDecodeMode ( u32 mpeg , u32 modeAddr )
2012-11-13 17:05:26 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( modeAddr ) ) {
WARN_LOG ( ME , " sceMpegAvcDecodeMode(%08x, %08x): invalid addresses " , mpeg , modeAddr ) ;
return - 1 ;
}
2012-12-24 18:04:05 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegAvcDecodeMode(%08x, %08x): bad mpeg handle " , mpeg , modeAddr ) ;
2012-12-24 18:04:05 +00:00
return - 1 ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegAvcDecodeMode(%08x, %08x) " , mpeg , modeAddr ) ;
2014-01-03 19:47:59 +00:00
int mode = Memory : : Read_U32 ( modeAddr ) ;
int pixelMode = Memory : : Read_U32 ( modeAddr + 4 ) ;
2014-02-01 15:56:34 +00:00
if ( pixelMode > = GE_CMODE_16BIT_BGR5650 & & pixelMode < = GE_CMODE_32BIT_ABGR8888 ) {
2014-01-03 19:47:59 +00:00
ctx - > videoPixelMode = pixelMode ;
2012-11-13 17:05:26 +00:00
} else {
2014-01-03 19:47:59 +00:00
ERROR_LOG ( ME , " sceMpegAvcDecodeMode(%i, %i): unknown pixelMode " , mode , pixelMode ) ;
2012-11-13 17:05:26 +00:00
}
2013-01-08 08:16:18 +00:00
return 0 ;
2012-11-13 17:05:26 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegQueryStreamOffset ( u32 mpeg , u32 bufferAddr , u32 offsetAddr )
2012-11-13 17:05:26 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( bufferAddr ) | | ! Memory : : IsValidAddress ( offsetAddr ) ) {
ERROR_LOG ( ME , " sceMpegQueryStreamOffset(%08x, %08x, %08x): invalid addresses " , mpeg , bufferAddr , offsetAddr ) ;
return - 1 ;
}
2012-11-13 17:05:26 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegQueryStreamOffset(%08x, %08x, %08x): bad mpeg handle " , mpeg , bufferAddr , offsetAddr ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
2012-12-24 18:04:05 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegQueryStreamOffset(%08x, %08x, %08x) " , mpeg , bufferAddr , offsetAddr ) ;
2012-12-24 18:04:05 +00:00
2012-11-13 17:05:26 +00:00
// Kinda destructive, no?
2013-07-01 17:04:19 +00:00
AnalyzeMpeg ( Memory : : GetPointer ( bufferAddr ) , ctx ) ;
2012-11-13 17:05:26 +00:00
if ( ctx - > mpegMagic ! = PSMF_MAGIC ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegQueryStreamOffset: Bad PSMF magic " ) ;
2013-03-10 19:55:19 +00:00
Memory : : Write_U32 ( 0 , offsetAddr ) ;
2013-01-08 02:03:48 +00:00
return ERROR_MPEG_INVALID_VALUE ;
2012-11-13 17:05:26 +00:00
} else if ( ctx - > mpegVersion < 0 ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegQueryStreamOffset: Bad version " ) ;
2013-03-10 19:55:19 +00:00
Memory : : Write_U32 ( 0 , offsetAddr ) ;
2013-01-08 02:03:48 +00:00
return ERROR_MPEG_BAD_VERSION ;
2012-11-13 17:05:26 +00:00
} else if ( ( ctx - > mpegOffset & 2047 ) ! = 0 | | ctx - > mpegOffset = = 0 ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegQueryStreamOffset: Bad offset " ) ;
2013-03-10 19:55:19 +00:00
Memory : : Write_U32 ( 0 , offsetAddr ) ;
2013-01-08 02:03:48 +00:00
return ERROR_MPEG_INVALID_VALUE ;
2012-11-13 17:05:26 +00:00
}
2013-03-10 19:55:19 +00:00
2012-11-13 17:05:26 +00:00
Memory : : Write_U32 ( ctx - > mpegOffset , offsetAddr ) ;
return 0 ;
}
2012-12-24 18:04:05 +00:00
u32 sceMpegQueryStreamSize ( u32 bufferAddr , u32 sizeAddr )
2012-11-13 17:05:26 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( bufferAddr ) | | ! Memory : : IsValidAddress ( sizeAddr ) ) {
ERROR_LOG ( ME , " sceMpegQueryStreamSize(%08x, %08x): invalid addresses " , bufferAddr , sizeAddr ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegQueryStreamSize(%08x, %08x) " , bufferAddr , sizeAddr ) ;
2012-11-13 17:05:26 +00:00
2013-03-10 19:55:19 +00:00
MpegContext ctx ;
2013-06-01 17:29:59 +00:00
ctx . mediaengine = 0 ;
2012-12-24 19:16:47 +00:00
2013-07-01 17:04:19 +00:00
AnalyzeMpeg ( Memory : : GetPointer ( bufferAddr ) , & ctx ) ;
2012-11-13 17:05:26 +00:00
2013-03-10 19:55:19 +00:00
if ( ctx . mpegMagic ! = PSMF_MAGIC ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegQueryStreamSize: Bad PSMF magic " ) ;
2013-03-10 19:55:19 +00:00
Memory : : Write_U32 ( 0 , sizeAddr ) ;
2012-11-13 17:05:26 +00:00
return ERROR_MPEG_INVALID_VALUE ;
2013-03-10 19:55:19 +00:00
} else if ( ( ctx . mpegOffset & 2047 ) ! = 0 ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegQueryStreamSize: Bad offset " ) ;
2013-03-10 19:55:19 +00:00
Memory : : Write_U32 ( 0 , sizeAddr ) ;
2012-11-13 17:05:26 +00:00
return ERROR_MPEG_INVALID_VALUE ;
}
2013-03-10 19:55:19 +00:00
Memory : : Write_U32 ( ctx . mpegStreamSize , sizeAddr ) ;
2012-11-13 17:05:26 +00:00
return 0 ;
}
2012-12-24 18:04:05 +00:00
int sceMpegRegistStream ( u32 mpeg , u32 streamType , u32 streamNum )
2012-11-13 17:05:26 +00:00
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
2014-01-03 19:47:59 +00:00
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegRegistStream(%08x, %i, %i): bad mpeg handle " , mpeg , streamType , streamNum ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
2012-12-24 18:04:05 +00:00
}
2013-09-07 20:02:55 +00:00
INFO_LOG ( ME , " sceMpegRegistStream(%08x, %i, %i) " , mpeg , streamType , streamNum ) ;
2012-11-13 17:05:26 +00:00
switch ( streamType ) {
case MPEG_AVC_STREAM :
ctx - > avcRegistered = true ;
2013-06-11 11:04:14 +00:00
ctx - > mediaengine - > setVideoStream ( streamNum ) ;
2012-11-13 17:05:26 +00:00
break ;
case MPEG_AUDIO_STREAM :
case MPEG_ATRAC_STREAM :
ctx - > atracRegistered = true ;
2013-06-11 11:04:14 +00:00
ctx - > mediaengine - > setAudioStream ( streamNum ) ;
2012-11-13 17:05:26 +00:00
break ;
case MPEG_PCM_STREAM :
ctx - > pcmRegistered = true ;
break ;
2013-01-08 08:16:18 +00:00
case MPEG_DATA_STREAM :
ctx - > dataRegistered = true ;
break ;
default :
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegRegistStream(%i) : unknown stream type " , streamType ) ;
2013-01-08 08:16:18 +00:00
break ;
2012-11-13 17:05:26 +00:00
}
// ...
2012-12-29 07:29:24 +00:00
u32 sid = streamIdGen + + ;
2012-11-13 17:05:26 +00:00
StreamInfo info ;
info . type = streamType ;
info . num = streamNum ;
2013-04-01 14:56:43 +00:00
info . needsReset = true ;
2012-11-13 17:05:26 +00:00
ctx - > streamMap [ sid ] = info ;
return sid ;
}
2012-12-24 18:04:05 +00:00
int sceMpegMallocAvcEsBuf ( u32 mpeg )
2012-11-13 17:05:26 +00:00
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegMallocAvcEsBuf(%08x): bad mpeg handle " , mpeg ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
2012-11-12 19:53:16 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegMallocAvcEsBuf(%08x) " , mpeg ) ;
2012-12-24 18:04:05 +00:00
2012-11-13 17:05:26 +00:00
// Doesn't actually malloc, just keeps track of a couple of flags
2014-02-01 15:56:34 +00:00
for ( int i = 0 ; i < MPEG_DATA_ES_BUFFERS ; i + + ) {
2012-11-13 17:05:26 +00:00
if ( ! ctx - > esBuffers [ i ] ) {
ctx - > esBuffers [ i ] = true ;
return i + 1 ;
}
}
// No es buffer
2012-11-12 19:53:16 +00:00
return 0 ;
}
2012-12-24 18:04:05 +00:00
int sceMpegFreeAvcEsBuf ( u32 mpeg , int esBuf )
2012-11-13 17:05:26 +00:00
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegFreeAvcEsBuf(%08x, %i): bad mpeg handle " , mpeg , esBuf ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
2012-12-24 18:04:05 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegFreeAvcEsBuf(%08x, %i) " , mpeg , esBuf ) ;
2012-12-24 18:04:05 +00:00
2012-11-13 17:05:26 +00:00
if ( esBuf = = 0 ) {
return ERROR_MPEG_INVALID_VALUE ;
}
2014-01-28 13:56:49 +00:00
2014-02-01 15:56:34 +00:00
if ( esBuf > = 1 & & esBuf < = MPEG_DATA_ES_BUFFERS ) {
2012-11-13 17:05:26 +00:00
// TODO: Check if it's already been free'd?
ctx - > esBuffers [ esBuf - 1 ] = false ;
}
2012-12-24 18:04:05 +00:00
return 0 ;
2012-11-13 17:05:26 +00:00
}
2012-12-24 18:04:05 +00:00
u32 sceMpegAvcDecode ( u32 mpeg , u32 auAddr , u32 frameWidth , u32 bufferAddr , u32 initAddr )
2012-11-12 19:53:16 +00:00
{
2012-11-13 17:05:26 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): bad mpeg handle " , mpeg , auAddr , frameWidth , bufferAddr , initAddr ) ;
2014-01-03 19:47:59 +00:00
return - 1 ;
2012-11-13 17:05:26 +00:00
}
2013-08-23 06:23:48 +00:00
if ( frameWidth = = 0 ) { // wtf, go sudoku passes in 0xcccccccc
2012-11-13 17:05:26 +00:00
if ( ! ctx - > defaultFrameWidth ) {
frameWidth = ctx - > avc . avcDetailFrameWidth ;
} else {
frameWidth = ctx - > defaultFrameWidth ;
}
}
SceMpegAu avcAu ;
2013-01-07 03:22:52 +00:00
avcAu . read ( auAddr ) ;
2012-11-13 17:05:26 +00:00
2013-06-10 22:51:10 +00:00
SceMpegRingBuffer ringbuffer = { 0 } ;
2014-01-03 19:47:59 +00:00
2013-06-10 22:51:10 +00:00
if ( Memory : : IsValidAddress ( ctx - > mpegRingbufferAddr ) ) {
Memory : : ReadStruct ( ctx - > mpegRingbufferAddr , & ringbuffer ) ;
} else {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " Bogus mpegringbufferaddr " ) ;
2013-06-10 22:51:10 +00:00
return - 1 ;
}
2012-11-13 17:05:26 +00:00
2013-06-08 07:25:27 +00:00
if ( ringbuffer . packetsRead = = 0 | | ctx - > mediaengine - > IsVideoEnd ( ) ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty " , mpeg , auAddr , frameWidth , bufferAddr , initAddr ) ;
2014-02-01 15:56:34 +00:00
return hleDelayResult ( ERROR_MPEG_AVC_DECODE_FATAL , " mpeg buffer empty " , avcEmptyDelayMs ) ;
2012-11-13 17:05:26 +00:00
}
u32 buffer = Memory : : Read_U32 ( bufferAddr ) ;
u32 init = Memory : : Read_U32 ( initAddr ) ;
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " *buffer = %08x, *init = %08x " , buffer , init ) ;
2012-11-13 17:05:26 +00:00
2013-06-02 07:29:45 +00:00
if ( ctx - > mediaengine - > stepVideo ( ctx - > videoPixelMode ) ) {
2013-12-11 16:21:01 +00:00
int bufferSize = ctx - > mediaengine - > writeVideoImage ( buffer , frameWidth , ctx - > videoPixelMode ) ;
2013-06-08 11:50:36 +00:00
gpu - > InvalidateCache ( buffer , bufferSize , GPU_INVALIDATE_SAFE ) ;
2013-06-08 07:25:27 +00:00
ctx - > avc . avcFrameStatus = 1 ;
ctx - > videoFrameCount + + ;
2012-11-13 17:05:26 +00:00
} else {
2013-06-08 07:25:27 +00:00
ctx - > avc . avcFrameStatus = 0 ;
2012-11-13 17:05:26 +00:00
}
2013-06-15 19:27:14 +00:00
ringbuffer . packetsFree = ctx - > mediaengine - > getRemainSize ( ) / 2048 ;
2012-11-13 17:05:26 +00:00
2013-06-13 13:03:17 +00:00
avcAu . pts = ctx - > mediaengine - > getVideoTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2012-11-13 17:05:26 +00:00
// Flush structs back to memory
2013-01-07 03:22:52 +00:00
avcAu . write ( auAddr ) ;
2012-11-13 17:05:26 +00:00
Memory : : WriteStruct ( ctx - > mpegRingbufferAddr , & ringbuffer ) ;
2014-01-27 14:07:30 +00:00
// Save the current frame's status to initAddr
Memory : : Write_U32 ( ctx - > avc . avcFrameStatus , initAddr ) ;
2013-06-30 12:24:20 +00:00
ctx - > avc . avcDecodeResult = MPEG_AVC_DECODE_SUCCESS ;
2012-11-13 17:05:26 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegAvcDecode(%08x, %08x, %i, %08x, %08x) " , mpeg , auAddr , frameWidth , bufferAddr , initAddr ) ;
2012-11-12 19:53:16 +00:00
2013-04-21 05:38:56 +00:00
if ( ctx - > videoFrameCount < = 1 )
return hleDelayResult ( 0 , " mpeg decode " , avcFirstDelayMs ) ;
else
return hleDelayResult ( 0 , " mpeg decode " , avcDecodeDelayMs ) ;
2013-06-01 17:29:59 +00:00
//hleEatMicro(3300);
//return hleDelayResult(0, "mpeg decode", 200);
2012-11-12 19:53:16 +00:00
}
u32 sceMpegAvcDecodeStop ( u32 mpeg , u32 frameWidth , u32 bufferAddr , u32 statusAddr )
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( bufferAddr ) | | ! Memory : : IsValidAddress ( statusAddr ) ) {
ERROR_LOG ( ME , " sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): invalid addresses " , mpeg , frameWidth , bufferAddr , statusAddr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): bad mpeg handle " , mpeg , frameWidth , bufferAddr , statusAddr ) ;
2013-01-08 08:16:18 +00:00
return - 1 ;
}
2014-01-03 19:47:59 +00:00
2014-02-01 15:56:34 +00:00
DEBUG_LOG ( ME , " sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x) " , mpeg , frameWidth , bufferAddr , statusAddr ) ;
2014-01-03 19:47:59 +00:00
2014-02-01 15:56:34 +00:00
// No last frame generated
2014-01-28 13:56:49 +00:00
Memory : : Write_U32 ( 0 , statusAddr ) ;
2012-11-12 19:53:16 +00:00
return 0 ;
}
2013-01-08 02:03:48 +00:00
u32 sceMpegUnRegistStream ( u32 mpeg , int streamUid )
2012-11-12 19:53:16 +00:00
{
2013-01-08 08:16:18 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
2014-01-03 19:47:59 +00:00
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegUnRegistStream(%08x, %i): bad mpeg handle " , mpeg , streamUid ) ;
2013-01-08 08:16:18 +00:00
return - 1 ;
}
2013-01-09 10:20:48 +00:00
StreamInfo info = { 0 } ;
2013-01-08 08:16:18 +00:00
switch ( info . type ) {
case MPEG_AVC_STREAM :
ctx - > avcRegistered = false ;
break ;
case MPEG_AUDIO_STREAM :
case MPEG_ATRAC_STREAM :
ctx - > atracRegistered = false ;
break ;
case MPEG_PCM_STREAM :
ctx - > pcmRegistered = false ;
break ;
case MPEG_DATA_STREAM :
ctx - > dataRegistered = false ;
break ;
default :
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegUnRegistStream(%i) : unknown streamID " , streamUid ) ;
2013-01-08 08:16:18 +00:00
break ;
}
ctx - > streamMap [ streamUid ] = info ;
info . type = - 1 ;
info . sid = - 1 ;
2013-04-01 14:56:43 +00:00
info . needsReset = true ;
2013-01-08 08:16:18 +00:00
ctx - > isAnalyzed = false ;
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-01 15:19:01 +00:00
}
2012-11-12 19:53:16 +00:00
2012-12-24 18:04:05 +00:00
int sceMpegAvcDecodeDetail ( u32 mpeg , u32 detailAddr )
2012-11-13 17:05:26 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( detailAddr ) ) {
WARN_LOG ( ME , " sceMpegAvcDecodeDetail(%08x, %08x): invalid addresses " , mpeg , detailAddr ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
2012-12-24 18:04:05 +00:00
}
2014-01-03 19:47:59 +00:00
2012-11-13 17:05:26 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
2014-01-03 19:47:59 +00:00
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegAvcDecodeDetail(%08x, %08x): bad mpeg handle " , mpeg , detailAddr ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
2012-12-24 18:04:05 +00:00
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegAvcDecodeDetail(%08x, %08x) " , mpeg , detailAddr ) ;
2012-11-13 17:05:26 +00:00
Memory : : Write_U32 ( ctx - > avc . avcDecodeResult , detailAddr + 0 ) ;
Memory : : Write_U32 ( ctx - > videoFrameCount , detailAddr + 4 ) ;
Memory : : Write_U32 ( ctx - > avc . avcDetailFrameWidth , detailAddr + 8 ) ;
Memory : : Write_U32 ( ctx - > avc . avcDetailFrameHeight , detailAddr + 12 ) ;
Memory : : Write_U32 ( 0 , detailAddr + 16 ) ;
Memory : : Write_U32 ( 0 , detailAddr + 20 ) ;
Memory : : Write_U32 ( 0 , detailAddr + 24 ) ;
Memory : : Write_U32 ( 0 , detailAddr + 28 ) ;
Memory : : Write_U32 ( ctx - > avc . avcFrameStatus , detailAddr + 32 ) ;
return 0 ;
}
2013-01-08 02:03:48 +00:00
u32 sceMpegAvcDecodeStopYCbCr ( u32 mpeg , u32 bufferAddr , u32 statusAddr )
2012-11-01 15:19:01 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( bufferAddr ) | | ! Memory : : IsValidAddress ( statusAddr ) ) {
ERROR_LOG ( ME , " UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): invalid addresses " , mpeg , bufferAddr , statusAddr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): bad mpeg handle " , mpeg , bufferAddr , statusAddr ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x) " , mpeg , bufferAddr , statusAddr ) ;
2014-01-18 18:56:41 +00:00
Memory : : Write_U32 ( 0 , statusAddr ) ;
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-01 15:19:01 +00:00
}
2012-11-12 19:53:16 +00:00
2012-12-24 19:07:11 +00:00
int sceMpegAvcDecodeYCbCr ( u32 mpeg , u32 auAddr , u32 bufferAddr , u32 initAddr )
2012-11-12 19:53:16 +00:00
{
2013-02-02 09:51:41 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle " , mpeg , auAddr , bufferAddr , initAddr ) ;
2014-01-03 19:47:59 +00:00
return - 1 ;
2013-02-02 09:51:41 +00:00
}
SceMpegAu avcAu ;
avcAu . read ( auAddr ) ;
2013-06-11 06:18:08 +00:00
SceMpegRingBuffer ringbuffer = { 0 } ;
if ( Memory : : IsValidAddress ( ctx - > mpegRingbufferAddr ) ) {
Memory : : ReadStruct ( ctx - > mpegRingbufferAddr , & ringbuffer ) ;
} else {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " Bogus mpegringbufferaddr " ) ;
2013-06-11 06:18:08 +00:00
return - 1 ;
}
2013-02-02 09:51:41 +00:00
2013-06-11 06:18:08 +00:00
if ( ringbuffer . packetsRead = = 0 | | ctx - > mediaengine - > IsVideoEnd ( ) ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty " , mpeg , auAddr , bufferAddr , initAddr ) ;
2014-02-01 15:56:34 +00:00
return hleDelayResult ( ERROR_MPEG_AVC_DECODE_FATAL , " mpeg buffer empty " , avcEmptyDelayMs ) ;
2013-02-02 09:51:41 +00:00
}
u32 buffer = Memory : : Read_U32 ( bufferAddr ) ;
u32 init = Memory : : Read_U32 ( initAddr ) ;
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " *buffer = %08x, *init = %08x " , buffer , init ) ;
2013-02-02 09:51:41 +00:00
2013-06-02 07:29:45 +00:00
if ( ctx - > mediaengine - > stepVideo ( ctx - > videoPixelMode ) ) {
2013-06-11 06:18:08 +00:00
// Don't draw here, we'll draw in the Csc func.
ctx - > avc . avcFrameStatus = 1 ;
ctx - > videoFrameCount + + ;
} else {
ctx - > avc . avcFrameStatus = 0 ;
2013-02-02 09:51:41 +00:00
}
2013-06-15 19:27:14 +00:00
ringbuffer . packetsFree = ctx - > mediaengine - > getRemainSize ( ) / 2048 ;
2013-02-02 09:51:41 +00:00
2013-06-13 13:03:17 +00:00
avcAu . pts = ctx - > mediaengine - > getVideoTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2013-02-02 09:51:41 +00:00
// Flush structs back to memory
avcAu . write ( auAddr ) ;
Memory : : WriteStruct ( ctx - > mpegRingbufferAddr , & ringbuffer ) ;
2014-01-27 14:07:30 +00:00
// Save the current frame's status to initAddr
Memory : : Write_U32 ( ctx - > avc . avcFrameStatus , initAddr ) ;
2013-06-30 12:24:20 +00:00
ctx - > avc . avcDecodeResult = MPEG_AVC_DECODE_SUCCESS ;
2013-02-02 09:51:41 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x) " , mpeg , auAddr , bufferAddr , initAddr ) ;
2013-02-02 09:51:41 +00:00
2013-04-21 05:38:56 +00:00
if ( ctx - > videoFrameCount < = 1 )
return hleDelayResult ( 0 , " mpeg decode " , avcFirstDelayMs ) ;
else
return hleDelayResult ( 0 , " mpeg decode " , avcDecodeDelayMs ) ;
2013-06-01 17:29:59 +00:00
//hleEatMicro(3300);
//return hleDelayResult(0, "mpeg decode", 200);
2012-11-12 19:53:16 +00:00
}
2012-12-24 18:04:05 +00:00
u32 sceMpegAvcDecodeFlush ( u32 mpeg )
2012-11-12 19:53:16 +00:00
{
2013-01-08 08:16:18 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
2014-01-03 19:47:59 +00:00
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcDecodeFlush(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcDecodeFlush(%08x) " , mpeg ) ;
2013-01-08 08:16:18 +00:00
if ( ctx - > videoFrameCount > 0 | | ctx - > audioFrameCount > 0 ) {
//__MpegFinish();
}
2012-11-12 19:53:16 +00:00
return 0 ;
}
2012-12-24 18:04:05 +00:00
int sceMpegInitAu ( u32 mpeg , u32 bufferAddr , u32 auPointer )
2012-11-01 15:19:01 +00:00
{
2012-11-13 17:05:26 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegInitAu(%08x, %i, %08x): bad mpeg handle " , mpeg , bufferAddr , auPointer ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
2012-11-01 15:19:01 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegInitAu(%08x, %i, %08x) " , mpeg , bufferAddr , auPointer ) ;
2012-12-24 18:04:05 +00:00
2012-11-13 17:05:26 +00:00
SceMpegAu sceAu ;
2013-01-07 03:22:52 +00:00
sceAu . read ( auPointer ) ;
2012-11-13 17:05:26 +00:00
2014-02-01 15:56:34 +00:00
if ( bufferAddr > = 1 & & bufferAddr < = ( u32 ) MPEG_DATA_ES_BUFFERS & & ctx - > esBuffers [ bufferAddr - 1 ] ) {
2012-11-13 17:05:26 +00:00
// This esbuffer has been allocated for Avc.
sceAu . esBuffer = bufferAddr ; // Can this be right??? not much of a buffer pointer..
sceAu . esSize = MPEG_AVC_ES_SIZE ;
sceAu . dts = 0 ;
sceAu . pts = 0 ;
2013-01-07 03:22:52 +00:00
sceAu . write ( auPointer ) ;
2012-11-13 17:05:26 +00:00
} else {
// This esbuffer has been left as Atrac.
sceAu . esBuffer = bufferAddr ;
sceAu . esSize = MPEG_ATRAC_ES_SIZE ;
sceAu . pts = 0 ;
sceAu . dts = UNKNOWN_TIMESTAMP ;
2013-01-07 03:22:52 +00:00
sceAu . write ( auPointer ) ;
2012-11-13 17:05:26 +00:00
}
return 0 ;
2012-11-12 19:53:16 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegQueryAtracEsSize ( u32 mpeg , u32 esSizeAddr , u32 outSizeAddr )
2012-11-12 19:53:16 +00:00
{
2012-11-13 17:05:26 +00:00
if ( ! Memory : : IsValidAddress ( esSizeAddr ) | | ! Memory : : IsValidAddress ( outSizeAddr ) ) {
2014-01-03 19:47:59 +00:00
ERROR_LOG ( ME , " sceMpegQueryAtracEsSize(%08x, %08x, %08x): invalid addresses " , mpeg , esSizeAddr , outSizeAddr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " sceMpegQueryAtracEsSize(%08x, %08x, %08x): bad mpeg handle " , mpeg , esSizeAddr , outSizeAddr ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegQueryAtracEsSize(%08x, %08x, %08x) " , mpeg , esSizeAddr , outSizeAddr ) ;
2014-01-03 19:47:59 +00:00
2012-11-13 17:05:26 +00:00
Memory : : Write_U32 ( MPEG_ATRAC_ES_SIZE , esSizeAddr ) ;
Memory : : Write_U32 ( MPEG_ATRAC_ES_OUTPUT_SIZE , outSizeAddr ) ;
return 0 ;
2012-11-12 19:53:16 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegRingbufferAvailableSize ( u32 ringbufferAddr )
2012-11-01 15:19:01 +00:00
{
2013-12-17 07:47:34 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ringbufferAddr ) ;
2013-06-22 15:39:25 +00:00
2013-06-25 13:51:39 +00:00
if ( ! ringbuffer . IsValid ( ) ) {
2014-01-06 07:12:16 +00:00
ERROR_LOG ( ME , " sceMpegRingbufferAvailableSize(%08x): invalid ringbuffer, should crash " , ringbufferAddr ) ;
return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS ;
2012-11-13 17:05:26 +00:00
}
2013-06-22 15:39:25 +00:00
MpegContext * ctx = getMpegCtx ( ringbuffer - > mpeg ) ;
if ( ! ctx ) {
2014-01-03 19:47:59 +00:00
ERROR_LOG ( ME , " sceMpegRingbufferAvailableSize(%08x): bad mpeg handle " , ringbufferAddr ) ;
2014-01-06 07:12:16 +00:00
return ERROR_MPEG_NOT_YET_INIT ;
2013-06-22 15:39:25 +00:00
}
2013-06-22 15:36:31 +00:00
hleEatCycles ( 2020 ) ;
2013-12-14 20:59:50 +00:00
static int lastFree = 0 ;
if ( lastFree ! = ringbuffer - > packetsFree ) {
DEBUG_LOG ( ME , " %i=sceMpegRingbufferAvailableSize(%08x) " , ringbuffer - > packetsFree , ringbufferAddr ) ;
lastFree = ringbuffer - > packetsFree ;
} else {
VERBOSE_LOG ( ME , " %i=sceMpegRingbufferAvailableSize(%08x) " , ringbuffer - > packetsFree , ringbufferAddr ) ;
}
2013-06-22 15:39:25 +00:00
return ringbuffer - > packetsFree ;
2012-11-01 15:19:01 +00:00
}
2013-01-06 18:54:33 +00:00
void PostPutAction : : run ( MipsCall & call ) {
2012-11-13 17:05:26 +00:00
SceMpegRingBuffer ringbuffer ;
Memory : : ReadStruct ( ringAddr_ , & ringbuffer ) ;
2012-12-24 19:21:40 +00:00
MpegContext * ctx = getMpegCtx ( ringbuffer . mpeg ) ;
2012-11-13 17:05:26 +00:00
int packetsAdded = currentMIPS - > r [ 2 ] ;
2013-07-01 17:04:19 +00:00
if ( ringbuffer . packetsRead = = 0 & & ctx - > mediaengine & & packetsAdded > 0 ) {
// init mediaEngine
2013-07-01 17:26:31 +00:00
AnalyzeMpeg ( ctx - > mpegheader , ctx ) ;
ctx - > mediaengine - > loadStream ( ctx - > mpegheader , 2048 , ringbuffer . packets * ringbuffer . packetSize ) ;
2013-07-01 17:04:19 +00:00
}
2012-11-13 17:05:26 +00:00
if ( packetsAdded > 0 ) {
if ( packetsAdded > ringbuffer . packetsFree ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegRingbufferPut clamping packetsAdded old=%i new=%i " , packetsAdded , ringbuffer . packetsFree ) ;
2012-11-13 17:05:26 +00:00
packetsAdded = ringbuffer . packetsFree ;
}
2013-08-13 06:33:52 +00:00
int actuallyAdded = ctx - > mediaengine = = NULL ? 8 : ctx - > mediaengine - > addStreamData ( Memory : : GetPointer ( ringbuffer . data ) , packetsAdded * 2048 ) / 2048 ;
2013-06-01 21:53:07 +00:00
if ( actuallyAdded ! = packetsAdded ) {
2013-09-07 20:02:55 +00:00
WARN_LOG_REPORT ( ME , " sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames. " ) ;
2013-06-01 21:53:07 +00:00
}
2012-11-13 17:05:26 +00:00
ringbuffer . packetsRead + = packetsAdded ;
ringbuffer . packetsWritten + = packetsAdded ;
ringbuffer . packetsFree - = packetsAdded ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " packetAdded: %i packetsRead: %i packetsTotal: %i " , packetsAdded , ringbuffer . packetsRead , ringbuffer . packets ) ;
2012-11-13 17:05:26 +00:00
Memory : : WriteStruct ( ringAddr_ , & ringbuffer ) ;
2013-01-06 23:53:44 +00:00
call . setReturnValue ( packetsAdded ) ;
2012-11-01 15:19:01 +00:00
}
2012-11-13 17:05:26 +00:00
2012-12-24 18:04:05 +00:00
// Program signals that it has written data to the ringbuffer and gets a callback ?
2012-11-13 17:05:26 +00:00
u32 sceMpegRingbufferPut ( u32 ringbufferAddr , u32 numPackets , u32 available )
2012-11-01 15:19:01 +00:00
{
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegRingbufferPut(%08x, %i, %i) " , ringbufferAddr , numPackets , available ) ;
2014-02-01 15:56:34 +00:00
2013-03-13 16:32:09 +00:00
numPackets = std : : min ( numPackets , available ) ;
2014-02-01 15:56:34 +00:00
if ( numPackets < = 0 ) {
2013-03-13 16:32:09 +00:00
return 0 ;
2014-02-01 15:56:34 +00:00
}
2013-03-14 14:03:26 +00:00
2012-11-13 17:05:26 +00:00
SceMpegRingBuffer ringbuffer ;
Memory : : ReadStruct ( ringbufferAddr , & ringbuffer ) ;
2012-12-24 19:21:40 +00:00
MpegContext * ctx = getMpegCtx ( ringbuffer . mpeg ) ;
2012-12-24 18:04:05 +00:00
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x " , ringbufferAddr , numPackets , available , ringbuffer . mpeg ) ;
2014-01-03 19:47:59 +00:00
return - 1 ;
2012-12-24 18:04:05 +00:00
}
2012-11-13 17:05:26 +00:00
// Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc
2013-07-29 03:28:32 +00:00
if ( ringbuffer . callback_addr ! = 0 ) {
2013-06-07 08:38:06 +00:00
PostPutAction * action = ( PostPutAction * ) __KernelCreateAction ( actionPostPut ) ;
2012-12-29 07:29:24 +00:00
action - > setRingAddr ( ringbufferAddr ) ;
2013-06-07 08:38:06 +00:00
// TODO: Should call this multiple times until we get numPackets.
// Normally this would be if it did not read enough, but also if available > packets.
// Should ultimately return the TOTAL number of returned packets.
u32 packetsThisRound = std : : min ( numPackets , ( u32 ) ringbuffer . packets ) ;
u32 args [ 3 ] = { ( u32 ) ringbuffer . data , packetsThisRound , ( u32 ) ringbuffer . callback_args } ;
2013-02-03 02:03:55 +00:00
__KernelDirectMipsCall ( ringbuffer . callback_addr , action , args , 3 , false ) ;
2012-11-13 17:05:26 +00:00
} else {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegRingbufferPut: callback_addr zero " ) ;
2012-11-13 17:05:26 +00:00
}
2012-11-12 22:32:46 +00:00
return 0 ;
2012-11-01 15:19:01 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegGetAvcAu ( u32 mpeg , u32 streamId , u32 auAddr , u32 attrAddr )
2012-11-07 14:44:48 +00:00
{
2012-11-13 17:05:26 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegGetAvcAu(%08x, %08x, %08x, %08x): bad mpeg handle " , mpeg , streamId , auAddr , attrAddr ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
SceMpegRingBuffer mpegRingbuffer ;
Memory : : ReadStruct ( ctx - > mpegRingbufferAddr , & mpegRingbuffer ) ;
SceMpegAu sceAu ;
2013-01-07 03:22:52 +00:00
sceAu . read ( auAddr ) ;
2012-11-13 17:05:26 +00:00
2013-03-31 17:56:28 +00:00
if ( mpegRingbuffer . packetsRead = = 0 | | mpegRingbuffer . packetsFree = = mpegRingbuffer . packets ) {
2014-02-01 15:56:34 +00:00
DEBUG_LOG ( ME , " ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x) " , mpeg , streamId , auAddr , attrAddr ) ;
2013-06-08 07:25:27 +00:00
sceAu . pts = - 1 ;
sceAu . dts = - 1 ;
sceAu . write ( auAddr ) ;
2013-04-21 06:17:10 +00:00
// TODO: Does this really reschedule?
2014-02-01 15:56:34 +00:00
return hleDelayResult ( ERROR_MPEG_NO_DATA , " mpeg get avc " , mpegDecodeErrorDelayMs ) ;
2012-11-13 17:05:26 +00:00
}
2013-04-01 14:56:43 +00:00
auto streamInfo = ctx - > streamMap . find ( streamId ) ;
2014-02-01 16:43:40 +00:00
if ( streamInfo ! = ctx - > streamMap . end ( ) ) {
ctx - > mediaengine - > setVideoStream ( streamInfo - > second . num ) ;
} else {
WARN_LOG_REPORT ( ME , " sceMpegGetAvcAu: invalid video stream %08x " , streamId ) ;
return - 1 ;
}
2014-01-14 18:31:09 +00:00
2014-01-03 19:47:59 +00:00
if ( streamInfo - > second . needsReset ) {
2013-04-01 14:56:43 +00:00
sceAu . pts = 0 ;
streamInfo - > second . needsReset = false ;
}
2013-06-01 17:29:59 +00:00
/*// Wait for audio if too much ahead
if ( ctx - > atracRegistered & & ( ctx - > mediaengine - > getVideoTimeStamp ( ) > ctx - > mediaengine - > getAudioTimeStamp ( ) + getMaxAheadTimestamp ( mpegRingbuffer ) ) )
2012-11-13 17:05:26 +00:00
{
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegGetAvcAu - video too much ahead " ) ;
2013-04-21 06:17:10 +00:00
// TODO: Does this really reschedule?
2014-02-01 15:56:34 +00:00
return hleDelayResult ( ERROR_MPEG_NO_DATA , " mpeg get avc " , mpegDecodeErrorDelayMs ) ;
2013-06-01 17:29:59 +00:00
} */
2012-11-13 17:05:26 +00:00
int result = 0 ;
2013-01-07 03:54:42 +00:00
2013-06-13 13:03:17 +00:00
sceAu . pts = ctx - > mediaengine - > getVideoTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2013-06-08 07:25:27 +00:00
sceAu . dts = sceAu . pts - videoTimestampStep ;
2013-06-04 12:25:03 +00:00
if ( ctx - > mediaengine - > IsVideoEnd ( ) ) {
2013-09-07 20:02:55 +00:00
INFO_LOG ( ME , " video end reach. pts: %i dts: %i " , ( int ) sceAu . pts , ( int ) ctx - > mediaengine - > getLastTimeStamp ( ) ) ;
2013-06-01 17:29:59 +00:00
mpegRingbuffer . packetsFree = mpegRingbuffer . packets ;
Memory : : WriteStruct ( ctx - > mpegRingbufferAddr , & mpegRingbuffer ) ;
2014-02-01 15:56:34 +00:00
result = ERROR_MPEG_NO_DATA ;
2012-11-13 17:05:26 +00:00
}
2013-01-07 03:22:52 +00:00
// The avcau struct may have been modified by mediaengine, write it back.
sceAu . write ( auAddr ) ;
2014-01-03 19:47:59 +00:00
// Jeanne d'Arc return 00000000 as attrAddr here and cause WriteToHardware error
2012-11-13 17:05:26 +00:00
if ( Memory : : IsValidAddress ( attrAddr ) ) {
Memory : : Write_U32 ( 1 , attrAddr ) ;
}
2014-01-03 19:47:59 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " %x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x) " , result , mpeg , streamId , auAddr , attrAddr ) ;
2013-04-21 06:17:10 +00:00
// TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something.
// There's definitely more to it, but ultimately it seems games should expect it to delay randomly.
2014-02-01 16:43:40 +00:00
return hleDelayResult ( result , " mpeg get avc " , 100 ) ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 02:03:48 +00:00
u32 sceMpegFinish ( )
2012-11-10 09:15:11 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! isMpegInit ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegFinish(...): not initialized " ) ;
2013-06-20 08:53:07 +00:00
// TODO: Need to properly hook module load/unload for this to work right.
//return ERROR_MPEG_NOT_YET_INIT;
} else {
2013-09-07 20:02:55 +00:00
INFO_LOG ( ME , " sceMpegFinish(...) " ) ;
2013-06-07 08:10:25 +00:00
}
isMpegInit = false ;
2012-11-13 17:05:26 +00:00
//__MpegFinish();
2013-06-07 08:10:25 +00:00
return hleDelayResult ( 0 , " mpeg finish " , 250 ) ;
2012-11-10 09:15:11 +00:00
}
2012-11-13 17:05:26 +00:00
u32 sceMpegQueryMemSize ( )
2012-11-10 09:15:11 +00:00
{
2014-01-29 22:03:10 +00:00
DEBUG_LOG ( ME , " %i = sceMpegQueryMemSize() " , MPEG_MEMSIZE ) ;
2014-01-28 13:56:49 +00:00
return MPEG_MEMSIZE ;
2012-11-10 09:15:11 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegGetAtracAu ( u32 mpeg , u32 streamId , u32 auAddr , u32 attrAddr )
2012-11-10 09:15:11 +00:00
{
2012-11-13 17:05:26 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegGetAtracAu(%08x, %08x, %08x, %08x): bad mpeg handle " , mpeg , streamId , auAddr , attrAddr ) ;
2012-11-13 17:05:26 +00:00
return - 1 ;
}
SceMpegRingBuffer mpegRingbuffer ;
Memory : : ReadStruct ( ctx - > mpegRingbufferAddr , & mpegRingbuffer ) ;
SceMpegAu sceAu ;
2013-01-07 03:22:52 +00:00
sceAu . read ( auAddr ) ;
2012-11-13 17:05:26 +00:00
2013-04-01 14:56:43 +00:00
auto streamInfo = ctx - > streamMap . find ( streamId ) ;
2014-01-03 19:47:59 +00:00
if ( streamInfo ! = ctx - > streamMap . end ( ) & & streamInfo - > second . needsReset ) {
2013-04-01 14:56:43 +00:00
sceAu . pts = 0 ;
streamInfo - > second . needsReset = false ;
}
2014-02-01 16:43:40 +00:00
if ( streamInfo ! = ctx - > streamMap . end ( ) ) {
2014-01-14 18:31:09 +00:00
ctx - > mediaengine - > setAudioStream ( streamInfo - > second . num ) ;
2014-02-01 16:43:40 +00:00
} else {
WARN_LOG_REPORT ( ME , " sceMpegGetAtracAu: invalid audio stream %08x " , streamId ) ;
2014-02-01 15:56:34 +00:00
}
2013-04-01 14:56:43 +00:00
2013-06-08 09:45:58 +00:00
// The audio can end earlier than the video does.
2013-07-02 09:20:46 +00:00
if ( mpegRingbuffer . packetsFree = = mpegRingbuffer . packets ) {
2014-02-01 15:56:34 +00:00
DEBUG_LOG ( ME , " ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x) " , mpeg , streamId , auAddr , attrAddr ) ;
2013-04-21 06:17:10 +00:00
// TODO: Does this really delay?
2014-02-01 15:56:34 +00:00
return hleDelayResult ( ERROR_MPEG_NO_DATA , " mpeg get atrac " , mpegDecodeErrorDelayMs ) ;
2013-03-31 17:56:28 +00:00
}
2013-06-01 17:29:59 +00:00
int result = 0 ;
2013-06-13 13:03:17 +00:00
sceAu . pts = ctx - > mediaengine - > getAudioTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2013-06-04 12:25:03 +00:00
if ( ctx - > mediaengine - > IsVideoEnd ( ) ) {
2013-09-07 20:02:55 +00:00
INFO_LOG ( ME , " video end reach. pts: %i dts: %i " , ( int ) sceAu . pts , ( int ) ctx - > mediaengine - > getLastTimeStamp ( ) ) ;
2013-06-01 17:29:59 +00:00
mpegRingbuffer . packetsFree = mpegRingbuffer . packets ;
Memory : : WriteStruct ( ctx - > mpegRingbufferAddr , & mpegRingbuffer ) ;
2012-11-13 17:05:26 +00:00
2014-02-01 15:56:34 +00:00
result = ERROR_MPEG_NO_DATA ;
2013-01-07 03:54:42 +00:00
}
2014-01-10 15:41:32 +00:00
if ( ctx - > mediaengine - > IsNoAudioData ( ) ) {
INFO_LOG ( ME , " Audio end reach. pts: %i dts: %i " , ( int ) sceAu . pts , ( int ) ctx - > mediaengine - > getLastTimeStamp ( ) ) ;
2014-02-01 15:56:34 +00:00
result = ERROR_MPEG_NO_DATA ;
2014-01-10 15:41:32 +00:00
}
2013-06-01 17:29:59 +00:00
sceAu . write ( auAddr ) ;
2014-01-03 19:47:59 +00:00
// 3rd birthday return 00000000 as attrAddr here and cause WriteToHardware error
2012-11-13 17:05:26 +00:00
if ( Memory : : IsValidAddress ( attrAddr ) ) {
Memory : : Write_U32 ( 0 , attrAddr ) ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " %x=sceMpegGetAtracAu(%08x, %08x, %08x, %08x) " , result , mpeg , streamId , auAddr , attrAddr ) ;
2013-04-21 06:17:10 +00:00
// TODO: Not clear on exactly when this delays.
2014-02-01 16:43:40 +00:00
return hleDelayResult ( result , " mpeg get atrac " , 100 ) ;
2012-11-10 09:15:11 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegQueryPcmEsSize ( u32 mpeg , u32 esSizeAddr , u32 outSizeAddr )
2012-11-10 09:15:11 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( esSizeAddr ) | | ! Memory : : IsValidAddress ( outSizeAddr ) ) {
ERROR_LOG ( ME , " sceMpegQueryPcmEsSize(%08x, %08x, %08x): invalid addresses " , mpeg , esSizeAddr , outSizeAddr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " sceMpegQueryPcmEsSize(%08x, %08x, %08x): bad mpeg handle " , mpeg , esSizeAddr , outSizeAddr ) ;
return - 1 ;
2012-11-13 17:05:26 +00:00
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegQueryPcmEsSize - bad pointers(%08x, %08x, %08x) " , mpeg , esSizeAddr , outSizeAddr ) ;
2014-01-03 19:47:59 +00:00
Memory : : Write_U32 ( MPEG_PCM_ES_SIZE , esSizeAddr ) ;
Memory : : Write_U32 ( MPEG_PCM_ES_OUTPUT_SIZE , outSizeAddr ) ;
return 0 ;
2012-11-10 09:15:11 +00:00
}
2012-11-13 17:05:26 +00:00
2013-01-08 02:03:48 +00:00
u32 sceMpegChangeGetAuMode ( u32 mpeg , int streamUid , int mode )
2012-11-10 09:15:11 +00:00
{
2013-01-08 09:04:51 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegChangeGetAuMode(%08x, %i, %i): bad mpeg handle " , mpeg , streamUid , mode ) ;
2013-01-08 09:04:51 +00:00
return - 1 ;
}
2013-01-09 10:20:48 +00:00
// NOTE: Where is the info supposed to come from?
StreamInfo info = { 0 } ;
2013-01-08 09:04:51 +00:00
info . sid = streamUid ;
2013-04-01 14:56:43 +00:00
if ( info . sid ) {
2013-01-08 09:04:51 +00:00
switch ( info . type ) {
case MPEG_AVC_STREAM :
2014-01-28 13:56:49 +00:00
if ( mode = = MPEG_AU_MODE_DECODE ) {
2013-01-08 09:04:51 +00:00
ctx - > ignoreAvc = false ;
} else if ( mode = = MPEG_AU_MODE_SKIP ) {
ctx - > ignoreAvc = true ;
}
break ;
case MPEG_AUDIO_STREAM :
case MPEG_ATRAC_STREAM :
2014-01-28 13:56:49 +00:00
if ( mode = = MPEG_AU_MODE_DECODE ) {
2013-01-08 09:04:51 +00:00
ctx - > ignoreAtrac = false ;
} else if ( mode = = MPEG_AU_MODE_SKIP ) {
ctx - > ignoreAtrac = true ;
}
break ;
case MPEG_PCM_STREAM :
2014-01-28 13:56:49 +00:00
if ( mode = = MPEG_AU_MODE_DECODE ) {
2013-01-08 09:04:51 +00:00
ctx - > ignorePcm = false ;
} else if ( mode = = MPEG_AU_MODE_SKIP ) {
ctx - > ignorePcm = true ;
}
break ;
default :
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAuMode(%08x, %i): unkown streamID " , mpeg , streamUid ) ;
2013-01-08 09:04:51 +00:00
break ;
}
} else {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAuMode(%08x, %i): unkown streamID " , mpeg , streamUid ) ;
2013-01-08 09:04:51 +00:00
}
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 08:16:18 +00:00
u32 sceMpegChangeGetAvcAuMode ( u32 mpeg , u32 stream_addr , int mode )
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( stream_addr ) ) {
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): invalid addresses " , mpeg , stream_addr , mode ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): bad mpeg handle " , mpeg , stream_addr , mode ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i) " , mpeg , stream_addr , mode ) ;
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 02:03:48 +00:00
u32 sceMpegGetPcmAu ( u32 mpeg , int streamUid , u32 auAddr , u32 attrAddr )
2012-11-10 09:15:11 +00:00
{
2014-01-03 19:47:59 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x): bad mpeg handle " , mpeg , streamUid , auAddr , attrAddr ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x) " , mpeg , streamUid , auAddr , attrAddr ) ;
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2014-01-28 13:56:49 +00:00
int __MpegRingbufferQueryPackNum ( u32 memorySize ) {
return memorySize / ( 2048 + 104 ) ;
}
2014-01-06 06:20:27 +00:00
int sceMpegRingbufferQueryPackNum ( u32 memorySize ) {
DEBUG_LOG ( ME , " sceMpegRingbufferQueryPackNum(%i) " , memorySize ) ;
2014-01-28 13:56:49 +00:00
return __MpegRingbufferQueryPackNum ( memorySize ) ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 02:03:48 +00:00
u32 sceMpegFlushAllStream ( u32 mpeg )
2012-11-10 09:15:11 +00:00
{
2013-01-08 09:04:51 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
2013-03-31 17:53:40 +00:00
if ( ! ctx ) {
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " sceMpegFlushAllStream(%08x): bad mpeg handle " , mpeg ) ;
2013-03-31 17:53:40 +00:00
return - 1 ;
}
2014-01-03 19:47:59 +00:00
2013-09-07 20:02:55 +00:00
WARN_LOG ( ME , " UNIMPL sceMpegFlushAllStream(%08x) " , mpeg ) ;
2013-03-31 17:53:40 +00:00
ctx - > isAnalyzed = false ;
2014-01-03 19:47:59 +00:00
if ( Memory : : IsValidAddress ( ctx - > mpegRingbufferAddr ) ) {
2013-03-31 17:53:40 +00:00
auto ringbuffer = Memory : : GetStruct < SceMpegRingBuffer > ( ctx - > mpegRingbufferAddr ) ;
ringbuffer - > packetsFree = ringbuffer - > packets ;
ringbuffer - > packetsRead = 0 ;
ringbuffer - > packetsWritten = 0 ;
2013-01-08 09:04:51 +00:00
}
2013-03-31 17:53:40 +00:00
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 08:16:18 +00:00
u32 sceMpegFlushStream ( u32 mpeg , int stream_addr )
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( stream_addr ) ) {
ERROR_LOG ( ME , " UNIMPL sceMpegFlushStream(%08x, %i): invalid addresses " , mpeg , stream_addr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegFlushStream(%08x, %i): bad mpeg handle " , mpeg , stream_addr ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegFlushStream(%08x, %i) " , mpeg , stream_addr ) ;
2013-01-08 08:16:18 +00:00
//__MpegFinish();
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 02:03:48 +00:00
u32 sceMpegAvcCopyYCbCr ( u32 mpeg , u32 sourceAddr , u32 YCbCrAddr )
2012-11-10 09:15:11 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( sourceAddr ) | | ! Memory : : IsValidAddress ( YCbCrAddr ) ) {
ERROR_LOG ( ME , " UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): invalid addresses " , mpeg , sourceAddr , YCbCrAddr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): bad mpeg handle " , mpeg , sourceAddr , YCbCrAddr ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x) " , mpeg , sourceAddr , YCbCrAddr ) ;
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 02:03:48 +00:00
u32 sceMpegAtracDecode ( u32 mpeg , u32 auAddr , u32 bufferAddr , int init )
2012-11-10 09:15:11 +00:00
{
2013-06-01 17:29:59 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2014-01-03 19:47:59 +00:00
WARN_LOG ( ME , " sceMpegAtracDecode(%08x, %08x, %08x, %i): bad mpeg handle " , mpeg , auAddr , bufferAddr , init ) ;
return - 1 ;
2013-06-01 17:29:59 +00:00
}
2014-01-03 19:47:59 +00:00
DEBUG_LOG ( ME , " sceMpegAtracDecode(%08x, %08x, %08x, %i) " , mpeg , auAddr , bufferAddr , init ) ;
2013-06-01 17:29:59 +00:00
SceMpegAu avcAu ;
avcAu . read ( auAddr ) ;
Memory : : Memset ( bufferAddr , 0 , MPEG_ATRAC_ES_OUTPUT_SIZE ) ;
2013-12-11 16:21:01 +00:00
ctx - > mediaengine - > getAudioSamples ( bufferAddr ) ;
2013-06-13 13:03:17 +00:00
avcAu . pts = ctx - > mediaengine - > getAudioTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2013-06-01 17:29:59 +00:00
avcAu . write ( auAddr ) ;
2013-04-21 05:42:51 +00:00
return hleDelayResult ( 0 , " mpeg atrac decode " , atracDecodeDelayMs ) ;
2013-06-01 17:29:59 +00:00
//hleEatMicro(4000);
//return hleDelayResult(0, "mpeg atrac decode", 200);
2012-11-10 09:15:11 +00:00
}
2012-11-13 17:05:26 +00:00
// YCbCr -> RGB color space conversion
2013-01-08 02:03:48 +00:00
u32 sceMpegAvcCsc ( u32 mpeg , u32 sourceAddr , u32 rangeAddr , int frameWidth , u32 destAddr )
2012-11-10 09:15:11 +00:00
{
2014-01-11 06:12:00 +00:00
if ( ! Memory : : IsValidAddress ( sourceAddr ) | | ! Memory : : IsValidAddress ( rangeAddr ) | | ! Memory : : IsValidAddress ( destAddr ) ) {
2014-01-03 19:47:59 +00:00
ERROR_LOG ( ME , " sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): invalid addresses " , mpeg , sourceAddr , rangeAddr , frameWidth , destAddr ) ;
2013-06-01 17:29:59 +00:00
return - 1 ;
2014-01-03 19:47:59 +00:00
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): bad mpeg handle " , mpeg , sourceAddr , rangeAddr , frameWidth , destAddr ) ;
2013-06-01 17:29:59 +00:00
return - 1 ;
2014-01-03 19:47:59 +00:00
}
DEBUG_LOG ( ME , " sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x) " , mpeg , sourceAddr , rangeAddr , frameWidth , destAddr ) ;
2014-01-28 13:56:49 +00:00
int x = Memory : : Read_U32 ( rangeAddr ) ;
2013-06-01 17:29:59 +00:00
int y = Memory : : Read_U32 ( rangeAddr + 4 ) ;
2014-01-28 13:56:49 +00:00
int width = Memory : : Read_U32 ( rangeAddr + 8 ) ;
int height = Memory : : Read_U32 ( rangeAddr + 12 ) ;
int destSize = ctx - > mediaengine - > writeVideoImageWithRange ( destAddr , frameWidth , ctx - > videoPixelMode , x , y , width , height ) ;
2013-06-01 17:29:59 +00:00
2013-06-08 11:50:36 +00:00
gpu - > InvalidateCache ( destAddr , destSize , GPU_INVALIDATE_SAFE ) ;
2014-01-05 00:46:50 +00:00
return hleDelayResult ( 0 , " mpeg avc csc " , avcDecodeDelayMs ) ;
2012-11-10 09:15:11 +00:00
}
2012-12-24 18:04:05 +00:00
u32 sceMpegRingbufferDestruct ( u32 ringbufferAddr )
2012-11-10 09:15:11 +00:00
{
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegRingbufferDestruct(%08x) " , ringbufferAddr ) ;
2014-01-06 06:20:27 +00:00
// Apparently, does nothing.
2012-11-13 17:05:26 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-08 02:03:48 +00:00
u32 sceMpegAvcInitYCbCr ( u32 mpeg , int mode , int width , int height , u32 ycbcr_addr )
2012-11-10 09:15:11 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( ycbcr_addr ) ) {
ERROR_LOG ( ME , " UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): invalid addresses " , mpeg , mode , width , height , ycbcr_addr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): bad mpeg handle " , mpeg , mode , width , height , ycbcr_addr ) ;
return - 1 ;
}
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x) " , mpeg , mode , width , height , ycbcr_addr ) ;
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2012-12-24 18:04:05 +00:00
int sceMpegAvcQueryYCbCrSize ( u32 mpeg , u32 mode , u32 width , u32 height , u32 resultAddr )
2012-11-10 09:15:11 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ( width & 15 ) ! = 0 | | ( height & 15 ) ! = 0 | | height > 272 | | width > 480 ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " sceMpegAvcQueryYCbCrSize: bad w/h %i x %i " , width , height ) ;
2013-01-08 09:04:51 +00:00
return ERROR_MPEG_INVALID_VALUE ;
2012-11-13 17:05:26 +00:00
}
2014-01-03 19:47:59 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( ME , " sceMpegAvcQueryYCbCrSize(%08x, %i, %i, %i, %08x) " , mpeg , mode , width , height , resultAddr ) ;
2012-11-10 09:15:11 +00:00
2012-11-13 17:05:26 +00:00
int size = ( width / 2 ) * ( height / 2 ) * 6 + 128 ;
Memory : : Write_U32 ( size , resultAddr ) ;
return 0 ;
2012-11-10 09:15:11 +00:00
}
2013-01-09 08:59:27 +00:00
u32 sceMpegQueryUserdataEsSize ( u32 mpeg , u32 esSizeAddr , u32 outSizeAddr )
2013-01-08 02:03:48 +00:00
{
2014-01-03 19:47:59 +00:00
if ( ! Memory : : IsValidAddress ( esSizeAddr ) | | ! Memory : : IsValidAddress ( outSizeAddr ) ) {
ERROR_LOG ( ME , " sceMpegQueryUserdataEsSize(%08x, %08x, %08x): invalid addresses " , mpeg , esSizeAddr , outSizeAddr ) ;
return - 1 ;
}
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " sceMpegQueryUserdataEsSize(%08x, %08x, %08x): bad mpeg handle " , mpeg , esSizeAddr , outSizeAddr ) ;
return - 1 ;
2013-01-09 08:59:27 +00:00
}
2014-01-03 19:47:59 +00:00
DEBUG_LOG ( ME , " sceMpegQueryUserdataEsSize(%08x, %08x, %08x) " , mpeg , esSizeAddr , outSizeAddr ) ;
Memory : : Write_U32 ( MPEG_DATA_ES_SIZE , esSizeAddr ) ;
Memory : : Write_U32 ( MPEG_DATA_ES_OUTPUT_SIZE , outSizeAddr ) ;
return 0 ;
2013-01-09 08:59:27 +00:00
}
2013-03-05 00:39:32 +00:00
u32 sceMpegAvcResourceGetAvcDecTopAddr ( u32 mpeg )
{
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcResourceGetAvcDecTopAddr(%08x) " , mpeg ) ;
2014-01-03 19:47:59 +00:00
// it's just a random address
2013-03-05 00:39:32 +00:00
return 0x12345678 ;
}
u32 sceMpegAvcResourceFinish ( u32 mpeg )
{
2014-01-03 19:47:59 +00:00
DEBUG_LOG ( ME , " UNIMPL sceMpegAvcResourceFinish(%08x) " , mpeg ) ;
2013-03-05 00:39:32 +00:00
return 0 ;
}
u32 sceMpegAvcResourceGetAvcEsBuf ( u32 mpeg )
{
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcResourceGetAvcEsBuf(%08x) " , mpeg ) ;
2013-03-05 00:39:32 +00:00
return 0 ;
}
u32 sceMpegAvcResourceInit ( u32 mpeg )
{
2014-02-01 16:19:45 +00:00
if ( mpeg ! = 1 ) {
return ERROR_MPEG_INVALID_VALUE ;
2013-03-05 00:39:32 +00:00
}
2014-01-03 19:47:59 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegAvcResourceInit(%08x) " , mpeg ) ;
2013-03-05 00:39:32 +00:00
return 0 ;
}
2013-01-09 21:42:22 +00:00
2013-10-04 16:04:51 +00:00
u32 convertABGRToYCbCr ( u32 abgr ) {
2013-09-18 10:19:08 +00:00
//see http://en.wikipedia.org/wiki/Yuv#Y.27UV444_to_RGB888_conversion for more information.
2013-10-04 16:04:51 +00:00
u8 r = ( abgr > > 0 ) & 0xFF ;
2013-09-18 06:05:09 +00:00
u8 g = ( abgr > > 8 ) & 0xFF ;
2013-10-04 16:04:51 +00:00
u8 b = ( abgr > > 16 ) & 0xFF ;
2013-09-18 06:05:09 +00:00
int y = 0.299f * r + 0.587f * g + 0.114f * b + 0 ;
int cb = - 0.169f * r - 0.331f * g + 0.499f * b + 128.0f ;
int cr = 0.499f * r - 0.418f * g - 0.0813f * b + 128.0f ;
// check yCbCr value
if ( y > 0xFF ) y = 0xFF ; if ( y < 0 ) y = 0 ;
if ( cb > 0xFF ) cb = 0xFF ; if ( cb < 0 ) cb = 0 ;
if ( cr > 0xFF ) cr = 0xFF ; if ( cr < 0 ) cr = 0 ;
return ( y < < 16 ) | ( cb < < 8 ) | cr ;
}
2013-03-10 07:21:55 +00:00
2013-09-18 08:19:05 +00:00
int __MpegAvcConvertToYuv420 ( const void * data , u32 bufferOutputAddr , int width , int height ) {
2013-09-18 06:05:09 +00:00
u32 * imageBuffer = ( u32 * ) data ;
int sizeY = width * height ;
int sizeCb = sizeY > > 2 ;
u8 * Y = ( u8 * ) Memory : : GetPointer ( bufferOutputAddr ) ;
u8 * Cb = Y + sizeY ;
u8 * Cr = Cb + sizeCb ;
for ( int y = 0 ; y < height ; + + y ) {
for ( int x = 0 ; x < width ; x + = 4 ) {
2013-10-04 16:04:51 +00:00
u32 abgr0 = imageBuffer [ x + 0 ] ;
u32 abgr1 = imageBuffer [ x + 1 ] ;
u32 abgr2 = imageBuffer [ x + 2 ] ;
u32 abgr3 = imageBuffer [ x + 3 ] ;
u32 yCbCr0 = convertABGRToYCbCr ( abgr0 ) ;
u32 yCbCr1 = convertABGRToYCbCr ( abgr1 ) ;
u32 yCbCr2 = convertABGRToYCbCr ( abgr2 ) ;
u32 yCbCr3 = convertABGRToYCbCr ( abgr3 ) ;
2013-09-18 06:05:09 +00:00
Y [ x + 0 ] = ( yCbCr0 > > 16 ) & 0xFF ;
Y [ x + 1 ] = ( yCbCr1 > > 16 ) & 0xFF ;
Y [ x + 2 ] = ( yCbCr2 > > 16 ) & 0xFF ;
Y [ x + 3 ] = ( yCbCr3 > > 16 ) & 0xFF ;
* Cb + + = ( yCbCr0 > > 8 ) & 0xFF ;
* Cr + + = yCbCr0 & 0xFF ;
}
imageBuffer + = width ;
Y + = width ;
}
return ( width < < 16 ) | height ;
}
int sceMpegAvcConvertToYuv420 ( u32 mpeg , u32 bufferOutputAddr , u32 unknown1 , int unknown2 )
2013-04-08 07:46:26 +00:00
{
2013-09-18 06:05:09 +00:00
if ( ! Memory : : IsValidAddress ( bufferOutputAddr ) ) {
2014-01-03 19:47:59 +00:00
ERROR_LOG ( ME , " sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): invalid addresses " , mpeg , bufferOutputAddr , unknown1 , unknown2 ) ;
return - 1 ;
2013-09-18 06:05:09 +00:00
}
2014-01-03 19:47:59 +00:00
2013-09-18 06:05:09 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
2014-01-03 19:47:59 +00:00
WARN_LOG ( ME , " sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): bad mpeg handle " , mpeg , bufferOutputAddr , unknown1 , unknown2 ) ;
return - 1 ;
2013-09-18 06:05:09 +00:00
}
2014-01-03 19:47:59 +00:00
2013-09-18 06:05:09 +00:00
DEBUG_LOG ( ME , " sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x) " , mpeg , bufferOutputAddr , unknown1 , unknown2 ) ;
const u8 * data = ctx - > mediaengine - > getFrameImage ( ) ;
int width = ctx - > mediaengine - > m_desWidth ;
int height = ctx - > mediaengine - > m_desHeight ;
if ( data ) {
2013-09-18 08:19:05 +00:00
__MpegAvcConvertToYuv420 ( data , bufferOutputAddr , width , height ) ;
2013-09-18 06:05:09 +00:00
}
2013-04-08 07:46:26 +00:00
return 0 ;
}
int sceMpegGetUserdataAu ( u32 mpeg , u32 streamUid , u32 auAddr , u32 resultAddr )
{
2014-01-03 19:47:59 +00:00
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " sceMpegGetUserdataAu(%08x, %08x, %08x, %08x): bad mpeg handle " , mpeg , streamUid , auAddr , resultAddr ) ;
return - 1 ;
}
DEBUG_LOG ( ME , " sceMpegGetUserdataAu(%08x, %08x, %08x, %08x) " , mpeg , streamUid , auAddr , resultAddr ) ;
2013-06-11 17:22:08 +00:00
2013-04-08 07:46:26 +00:00
// TODO: Are these at all right? Seen in Phantasy Star Portable 2.
Memory : : Write_U32 ( 0 , resultAddr ) ;
Memory : : Write_U32 ( 0 , resultAddr + 4 ) ;
2013-06-11 17:22:08 +00:00
// We currently can't demux userdata so this seems like the best thing to return in the meantime..
// Then we probably shouldn't do the above writes? but it works...
return ERROR_MPEG_NO_DATA ;
2013-04-08 07:46:26 +00:00
}
2013-03-10 07:21:55 +00:00
2014-01-28 13:56:49 +00:00
u32 sceMpegNextAvcRpAu ( u32 mpeg , u32 streamUid )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegNextAvcRpAu(%08x, %08x): bad mpeg handle " , mpeg , streamUid ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegNextAvcRpAu(%08x, %08x) " , mpeg , streamUid ) ;
return 0 ;
}
u32 sceMpegGetAvcNalAu ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegGetAvcNalAu(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegGetAvcNalAu(%08x) " , mpeg ) ;
return 0 ;
}
u32 sceMpegAvcDecodeDetailIndex ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcDecodeDetailIndex(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegAvcDecodeDetailIndex(%08x) " , mpeg ) ;
return 0 ;
}
u32 sceMpegAvcDecodeDetail2 ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcDecodeDetail2(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegAvcDecodeDetail2(%08x) " , mpeg ) ;
return 0 ;
}
u32 sceMpegGetAvcEsAu ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegGetAvcEsAu(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegGetAvcEsAu(%08x) " , mpeg ) ;
return 0 ;
}
2014-01-28 14:03:11 +00:00
u32 sceMpegAvcCscInfo ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcCscInfo(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegAvcCscInfo(%08x) " , mpeg ) ;
return 0 ;
}
u32 sceMpegAvcCscMode ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegAvcCscMode(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegAvcCscMode(%08x) " , mpeg ) ;
return 0 ;
}
u32 sceMpegFlushAu ( u32 mpeg )
{
MpegContext * ctx = getMpegCtx ( mpeg ) ;
if ( ! ctx ) {
WARN_LOG ( ME , " UNIMPL sceMpegFlushAu(%08x): bad mpeg handle " , mpeg ) ;
return - 1 ;
}
ERROR_LOG_REPORT ( ME , " UNIMPL sceMpegFlushAu(%08x) " , mpeg ) ;
return 0 ;
}
2012-11-01 15:19:01 +00:00
const HLEFunction sceMpeg [ ] =
{
2012-12-24 18:04:05 +00:00
{ 0xe1ce83a7 , WrapI_UUUU < sceMpegGetAtracAu > , " sceMpegGetAtracAu " } ,
{ 0xfe246728 , WrapI_UUUU < sceMpegGetAvcAu > , " sceMpegGetAvcAu " } ,
2012-11-13 17:05:26 +00:00
{ 0xd8c5f121 , WrapU_UUUUUUU < sceMpegCreate > , " sceMpegCreate " } ,
2012-12-24 18:04:05 +00:00
{ 0xf8dcb679 , WrapI_UUU < sceMpegQueryAtracEsSize > , " sceMpegQueryAtracEsSize " } ,
2012-11-13 17:05:26 +00:00
{ 0xc132e22f , WrapU_V < sceMpegQueryMemSize > , " sceMpegQueryMemSize " } ,
2012-12-24 18:04:05 +00:00
{ 0x21ff80e4 , WrapI_UUU < sceMpegQueryStreamOffset > , " sceMpegQueryStreamOffset " } ,
2012-11-13 17:05:26 +00:00
{ 0x611e9e11 , WrapU_UU < sceMpegQueryStreamSize > , " sceMpegQueryStreamSize " } ,
2012-12-24 18:04:05 +00:00
{ 0x42560f23 , WrapI_UUU < sceMpegRegistStream > , " sceMpegRegistStream " } ,
2013-01-08 02:03:48 +00:00
{ 0x591a4aa2 , WrapU_UI < sceMpegUnRegistStream > , " sceMpegUnRegistStream " } ,
{ 0x707b7629 , WrapU_U < sceMpegFlushAllStream > , " sceMpegFlushAllStream " } ,
2013-01-08 08:16:18 +00:00
{ 0x500F0429 , WrapU_UI < sceMpegFlushStream > , " sceMpegFlushStream " } ,
2012-12-24 18:04:05 +00:00
{ 0xa780cf7e , WrapI_U < sceMpegMallocAvcEsBuf > , " sceMpegMallocAvcEsBuf " } ,
{ 0xceb870b1 , WrapI_UI < sceMpegFreeAvcEsBuf > , " sceMpegFreeAvcEsBuf " } ,
{ 0x167afd9e , WrapI_UUU < sceMpegInitAu > , " sceMpegInitAu " } ,
2013-01-08 02:03:48 +00:00
{ 0x682a619b , WrapU_V < sceMpegInit > , " sceMpegInit " } ,
2012-12-24 18:04:05 +00:00
{ 0x606a4649 , WrapI_U < sceMpegDelete > , " sceMpegDelete " } ,
2013-01-08 02:03:48 +00:00
{ 0x874624d6 , WrapU_V < sceMpegFinish > , " sceMpegFinish " } ,
{ 0x800c44df , WrapU_UUUI < sceMpegAtracDecode > , " sceMpegAtracDecode " } ,
2012-11-12 19:53:16 +00:00
{ 0x0e3c2e9d , & WrapU_UUUUU < sceMpegAvcDecode > , " sceMpegAvcDecode " } ,
{ 0x740fccd1 , & WrapU_UUUU < sceMpegAvcDecodeStop > , " sceMpegAvcDecodeStop " } ,
{ 0x4571cc64 , & WrapU_U < sceMpegAvcDecodeFlush > , " sceMpegAvcDecodeFlush " } ,
2012-12-24 18:04:05 +00:00
{ 0x0f6c18d7 , & WrapI_UU < sceMpegAvcDecodeDetail > , " sceMpegAvcDecodeDetail " } ,
{ 0xa11c7026 , WrapI_UU < sceMpegAvcDecodeMode > , " sceMpegAvcDecodeMode " } ,
2012-11-12 22:32:46 +00:00
{ 0x37295ed8 , WrapU_UUUUUU < sceMpegRingbufferConstruct > , " sceMpegRingbufferConstruct " } ,
2012-11-13 17:05:26 +00:00
{ 0x13407f13 , WrapU_U < sceMpegRingbufferDestruct > , " sceMpegRingbufferDestruct " } ,
{ 0xb240a59e , WrapU_UUU < sceMpegRingbufferPut > , " sceMpegRingbufferPut " } ,
2012-12-24 18:04:05 +00:00
{ 0xb5f6dc87 , WrapI_U < sceMpegRingbufferAvailableSize > , " sceMpegRingbufferAvailableSize " } ,
2012-11-12 22:32:46 +00:00
{ 0xd7a29f46 , WrapU_I < sceMpegRingbufferQueryMemSize > , " sceMpegRingbufferQueryMemSize " } ,
2014-01-06 06:20:27 +00:00
{ 0x769BEBB6 , WrapI_U < sceMpegRingbufferQueryPackNum > , " sceMpegRingbufferQueryPackNum " } ,
2012-12-24 18:04:05 +00:00
{ 0x211a057c , WrapI_UUUUU < sceMpegAvcQueryYCbCrSize > , " sceMpegAvcQueryYCbCrSize " } ,
2012-12-24 19:07:11 +00:00
{ 0xf0eb1125 , WrapI_UUUU < sceMpegAvcDecodeYCbCr > , " sceMpegAvcDecodeYCbCr " } ,
2013-01-08 02:03:48 +00:00
{ 0xf2930c9c , WrapU_UUU < sceMpegAvcDecodeStopYCbCr > , " sceMpegAvcDecodeStopYCbCr " } ,
{ 0x67179b1b , WrapU_UIIIU < sceMpegAvcInitYCbCr > , " sceMpegAvcInitYCbCr " } ,
{ 0x0558B075 , WrapU_UUU < sceMpegAvcCopyYCbCr > , " sceMpegAvcCopyYCbCr " } ,
{ 0x31bd0272 , WrapU_UUUIU < sceMpegAvcCsc > , " sceMpegAvcCsc " } ,
{ 0x9DCFB7EA , WrapU_UII < sceMpegChangeGetAuMode > , " sceMpegChangeGetAuMode " } ,
{ 0x8C1E027D , WrapU_UIUU < sceMpegGetPcmAu > , " sceMpegGetPcmAu " } ,
2012-12-24 18:04:05 +00:00
{ 0xC02CF6B5 , WrapI_UUU < sceMpegQueryPcmEsSize > , " sceMpegQueryPcmEsSize " } ,
2013-01-08 02:03:48 +00:00
{ 0xC45C99CC , WrapU_UUU < sceMpegQueryUserdataEsSize > , " sceMpegQueryUserdataEsSize " } ,
2013-01-08 08:16:18 +00:00
{ 0x234586AE , WrapU_UUI < sceMpegChangeGetAvcAuMode > , " sceMpegChangeGetAvcAuMode " } ,
2013-03-05 00:39:32 +00:00
{ 0x63B9536A , WrapU_U < sceMpegAvcResourceGetAvcDecTopAddr > , " sceMpegAvcResourceGetAvcDecTopAddr " } ,
{ 0x8160a2fe , WrapU_U < sceMpegAvcResourceFinish > , " sceMpegAvcResourceFinish " } ,
{ 0xaf26bb01 , WrapU_U < sceMpegAvcResourceGetAvcEsBuf > , " sceMpegAvcResourceGetAvcEsBuf " } ,
{ 0xfcbdb5ad , WrapU_U < sceMpegAvcResourceInit > , " sceMpegAvcResourceInit " } ,
2013-03-10 07:21:55 +00:00
{ 0xF5E7EA31 , WrapI_UUUI < sceMpegAvcConvertToYuv420 > , " sceMpegAvcConvertToYuv420 " } ,
2013-04-08 07:46:26 +00:00
{ 0x01977054 , WrapI_UUUU < sceMpegGetUserdataAu > , " sceMpegGetUserdataAu " } ,
2014-01-28 13:56:49 +00:00
{ 0x3c37a7a6 , WrapU_UU < sceMpegNextAvcRpAu > , " sceMpegNextAvcRpAu " } ,
{ 0x11f95cf1 , WrapU_U < sceMpegGetAvcNalAu > , " sceMpegGetAvcNalAu " } ,
{ 0xab0e9556 , WrapU_U < sceMpegAvcDecodeDetailIndex > , " sceMpegAvcDecodeDetailIndex " } ,
{ 0xcf3547a2 , WrapU_U < sceMpegAvcDecodeDetail2 > , " sceMpegAvcDecodeDetail2 " } ,
{ 0x921fcccf , WrapU_U < sceMpegGetAvcEsAu > , " sceMpegGetAvcEsAu " } ,
2014-01-28 14:03:11 +00:00
{ 0xE95838F6 , WrapU_U < sceMpegAvcCscInfo > , " sceMpegAvcCscInfo " } ,
{ 0xD1CE4950 , WrapU_U < sceMpegAvcCscMode > , " sceMpegAvcCscMode " } ,
{ 0xDBB60658 , WrapU_U < sceMpegFlushAu > , " sceMpegFlushAu " } ,
2013-06-30 18:40:52 +00:00
{ 0xd4dd6e75 , 0 , " sceMpeg_D4DD6E75 " } ,
{ 0x11cab459 , 0 , " sceMpeg_11CAB459 " } ,
{ 0xc345ded2 , 0 , " sceMpeg_C345DED2 " } ,
{ 0xb27711a8 , 0 , " sceMpeg_B27711A8 " } ,
{ 0x988e9e12 , 0 , " sceMpeg_988E9E12 " } ,
2012-11-01 15:19:01 +00:00
} ;
void Register_sceMpeg ( )
{
RegisterModule ( " sceMpeg " , ARRAY_SIZE ( sceMpeg ) , sceMpeg ) ;
}