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/.
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>
2017-02-20 10:12:39 +00:00
# include <memory>
2012-11-12 19:53:16 +00:00
2017-08-31 15:13:18 +00:00
# include "Common/Swap.h"
2014-03-02 01:18:38 +00:00
# include "Core/HLE/sceMpeg.h"
2014-03-15 18:44:02 +00:00
# include "Core/HLE/sceKernelModule.h"
2014-03-02 01:18:38 +00:00
# include "Core/HLE/sceKernelThread.h"
# include "Core/HLE/HLE.h"
2014-03-15 18:22:19 +00:00
# include "Core/HLE/FunctionWrappers.h"
2014-03-02 01:18:38 +00:00
# include "Core/HW/MediaEngine.h"
2013-06-01 21:53:07 +00:00
# include "Core/Config.h"
2015-04-06 01:03:50 +00:00
# include "Core/MemMapHelpers.h"
2013-06-01 21:53:07 +00:00
# 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
2014-02-16 15:23:17 +00:00
// PSMF analysis results.
static const int PSMF_VERSION_0012 = 0x32313030 ;
static const int PSMF_VERSION_0013 = 0x33313030 ;
static const int PSMF_VERSION_0014 = 0x34313030 ;
static const int PSMF_VERSION_0015 = 0x35313030 ;
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 ;
2016-06-04 21:05:34 +00:00
static const u32 MPEG_MEMSIZE_0104 = 0x0b3DB ;
static const u32 MPEG_MEMSIZE_0105 = 0x10000 ; // 64k.
static const int MPEG_AVC_DECODE_SUCCESS = 1 ; // Internal value.
2012-11-12 19:53:16 +00:00
2013-04-21 05:38:56 +00:00
static const int atracDecodeDelayMs = 3000 ;
static const int avcFirstDelayMs = 3600 ;
2015-03-03 23:21:38 +00:00
static const int avcCscDelayMs = 4000 ;
2013-04-21 05:38:56 +00:00
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 ;
2014-04-04 21:01:25 +00:00
// For PMP media
static u32 pmp_videoSource = 0 ; //pointer to the video source (SceMpegLLi structure)
static int pmp_nBlocks = 0 ; //number of blocks received in the last sceMpegbase_BEA18F91 call
static std : : list < AVFrame * > pmp_queue ; //list of pmp video frames have been decoded and will be played
2014-04-07 03:16:45 +00:00
static std : : list < u32 > pmp_ContextList ; //list of pmp media contexts
2014-04-04 21:01:25 +00:00
static bool pmp_oldStateLoaded = false ; // for dostate
# ifdef USE_FFMPEG
2014-06-22 12:01:23 +00:00
2014-04-04 21:01:25 +00:00
extern " C " {
2015-02-03 19:46:51 +00:00
# include "libavformat/avformat.h"
2016-05-28 17:11:53 +00:00
# include "libavutil/imgutils.h"
2015-02-03 19:46:51 +00:00
# include "libswscale/swscale.h"
2014-04-04 21:01:25 +00:00
}
2014-06-22 12:01:23 +00:00
static AVPixelFormat pmp_want_pix_fmt ;
2014-04-04 21:01:25 +00:00
# endif
struct SceMpegLLI
{
u32 pSrc ;
u32 pDst ;
u32 Next ;
int iSize ;
} ;
2014-03-15 09:45:39 +00:00
void SceMpegAu : : read ( u32 addr ) {
Memory : : ReadStruct ( addr , this ) ;
pts = ( pts & 0xFFFFFFFFULL ) < < 32 | ( ( ( u64 ) pts ) > > 32 ) ;
dts = ( dts & 0xFFFFFFFFULL ) < < 32 | ( ( ( u64 ) dts ) > > 32 ) ;
}
void SceMpegAu : : write ( u32 addr ) {
pts = ( pts & 0xFFFFFFFFULL ) < < 32 | ( ( ( u64 ) pts ) > > 32 ) ;
dts = ( dts & 0xFFFFFFFFULL ) < < 32 | ( ( ( u64 ) dts ) > > 32 ) ;
Memory : : WriteStruct ( addr , this ) ;
}
2016-03-13 14:02:14 +00:00
/*
// Currently unused
2014-12-08 09:40:08 +00:00
static 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
}
2016-03-13 14:02:14 +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 {
2016-08-05 17:46:11 +00:00
MpegContext ( ) : ringbufferNeedsReverse ( false ) , mediaengine ( nullptr ) {
2015-01-04 05:46:40 +00:00
memcpy ( mpegheader , defaultMpegheader , 2048 ) ;
}
2013-02-04 16:24:32 +00:00
~ MpegContext ( ) {
2015-01-04 05:46:40 +00:00
delete mediaengine ;
2013-02-04 16:24:32 +00:00
}
2012-12-29 11:19:13 +00:00
void DoState ( PointerWrap & p ) {
2015-01-04 05:46:40 +00:00
auto s = p . Section ( " MpegContext " , 1 , 2 ) ;
2013-09-15 03:23:03 +00:00
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 ) ;
2015-01-04 05:46:40 +00:00
ringbufferNeedsReverse = s < 2 ;
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 ;
2015-01-04 05:46:40 +00:00
bool ringbufferNeedsReverse ;
2012-11-13 17:05:26 +00:00
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 ;
2014-03-02 01:18:38 +00:00
static int mpegLibVersion ;
2012-12-29 07:29:24 +00:00
static u32 streamIdGen ;
static int actionPostPut ;
2012-12-24 18:31:33 +00:00
static std : : map < u32 , MpegContext * > mpegMap ;
2014-12-08 09:40:08 +00:00
static MpegContext * getMpegCtx ( u32 mpegAddr ) {
2014-02-08 08:46:55 +00:00
if ( ! Memory : : IsValidAddress ( mpegAddr ) )
2015-01-04 05:46:40 +00:00
return nullptr ;
2014-02-08 08:46:55 +00:00
2012-12-24 18:31:33 +00:00
u32 mpeg = Memory : : Read_U32 ( mpegAddr ) ;
2015-01-04 05:46:40 +00:00
auto found = mpegMap . find ( mpeg ) ;
if ( found = = mpegMap . end ( ) )
return nullptr ;
MpegContext * res = found - > second ;
// Take this opportunity to upgrade savestates if necessary.
if ( res - > ringbufferNeedsReverse ) {
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( res - > mpegRingbufferAddr ) ;
ringbuffer - > packetsAvail = ringbuffer - > packets - ringbuffer - > packetsAvail ;
res - > ringbufferNeedsReverse = false ;
}
return res ;
2012-11-13 17:05:26 +00:00
}
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 ;
2016-06-05 00:34:49 +00:00
buf - > packetsWritePos = 0 ;
2015-01-04 02:59:56 +00:00
buf - > packetsAvail = 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-03-02 18:40:54 +00:00
// This isn't in ver 0104, but it is in 0105.
if ( mpegLibVersion > = 0x0105 )
2014-03-02 01:19:55 +00:00
buf - > gp = __KernelGetModuleGP ( __KernelGetCurThreadModuleId ( ) ) ;
2014-01-06 06:20:27 +00:00
}
2012-11-13 17:05:26 +00:00
2014-12-08 09:40:08 +00:00
static u32 convertTimestampToDate ( u32 ts ) {
2012-11-12 19:53:16 +00:00
return ts ; // TODO
}
2014-12-08 09:40:08 +00:00
static u32 getMpegVersion ( u32 mpegRawVersion ) {
2014-04-18 12:27:17 +00:00
switch ( mpegRawVersion ) {
case PSMF_VERSION_0012 : return MPEG_VERSION_0012 ;
case PSMF_VERSION_0013 : return MPEG_VERSION_0013 ;
case PSMF_VERSION_0014 : return MPEG_VERSION_0014 ;
case PSMF_VERSION_0015 : return MPEG_VERSION_0015 ;
2014-04-18 13:32:02 +00:00
default : return - 1 ;
2014-04-18 12:27:17 +00:00
}
}
2014-12-08 09:40:08 +00:00
static 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 ) ;
2014-04-18 12:27:17 +00:00
ctx - > mpegVersion = getMpegVersion ( ctx - > mpegRawVersion ) ;
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 ;
2014-02-04 01:21:16 +00:00
// Sanity Check ctx->mpegFirstTimestamp
if ( ctx - > mpegFirstTimestamp ! = 90000 ) {
2014-02-04 02:59:34 +00:00
WARN_LOG_REPORT ( ME , " Unexpected mpeg first timestamp: %llx / %lld " , ctx - > mpegFirstTimestamp , ctx - > mpegFirstTimestamp ) ;
2014-02-04 01:21:16 +00:00
}
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
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ringbuffer . IsValid ( ) ) {
ctx - > mediaengine - > loadStream ( buffer , ctx - > mpegOffset , ringbuffer - > packets * ringbuffer - > packetSize ) ;
} else {
// TODO: Does this make any sense?
ctx - > mediaengine - > loadStream ( buffer , ctx - > mpegOffset , 0 ) ;
}
2013-09-21 04:03:54 +00:00
}
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 ; }
2014-12-08 20:14:35 +00:00
void DoState ( PointerWrap & p ) override {
auto s = p . Section ( " PostPutAction " , 1 ) ;
if ( ! s )
return ;
2013-09-15 03:23:03 +00:00
p . Do ( ringAddr_ ) ;
}
2014-12-08 20:14:35 +00:00
void run ( MipsCall & call ) override ;
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 ( ) {
2013-06-07 08:10:25 +00:00
isMpegInit = false ;
2014-03-02 01:18:38 +00:00
mpegLibVersion = 0x010A ;
streamIdGen = 1 ;
2012-12-29 07:29:24 +00:00
actionPostPut = __KernelRegisterActionType ( PostPutAction : : Create ) ;
2013-01-20 13:30:16 +00:00
2014-03-31 15:59:11 +00:00
# ifdef USE_FFMPEG
2013-01-20 13:30:16 +00:00
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-03-02 01:18:38 +00:00
auto s = p . Section ( " sceMpeg " , 1 , 2 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2014-03-02 01:18:38 +00:00
if ( s < 2 ) {
int oldLastMpeg = - 1 ;
2014-03-24 08:15:37 +00:00
bool oldIsMpegAnalyzed = false ;
2014-03-02 01:18:38 +00:00
p . Do ( oldLastMpeg ) ;
p . Do ( streamIdGen ) ;
2014-03-24 08:15:37 +00:00
p . Do ( oldIsMpegAnalyzed ) ;
2014-03-02 01:18:38 +00:00
// Let's assume the oldest version.
mpegLibVersion = 0x0101 ;
} else {
p . Do ( streamIdGen ) ;
p . Do ( mpegLibVersion ) ;
}
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
2014-03-02 01:18:38 +00:00
void __MpegLoadModule ( int version ) {
mpegLibVersion = version ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegInit ( ) {
2013-06-07 08:10:25 +00:00
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-12-08 09:40:08 +00:00
static u32 __MpegRingbufferQueryMemSize ( int packets ) {
2014-01-06 06:20:27 +00:00
return packets * ( 104 + 2048 ) ;
}
2014-12-08 09:40:08 +00:00
static 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-12-08 09:40:08 +00:00
static u32 sceMpegRingbufferConstruct ( u32 ringbufferAddr , u32 numPackets , u32 data , u32 size , u32 callbackAddr , u32 callbackArg ) {
2014-01-06 06:20:27 +00:00
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 ;
}
2016-06-04 21:05:34 +00:00
static u32 MpegRequiredMem ( ) {
if ( mpegLibVersion < 0x0105 ) {
return MPEG_MEMSIZE_0104 ;
}
return MPEG_MEMSIZE_0105 ;
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2016-06-04 21:05:34 +00:00
if ( size < MpegRequiredMem ( ) ) {
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
}
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ringbufferAddr ) ;
if ( ringbuffer . IsValid ( ) ) {
if ( ringbuffer - > packetSize = = 0 ) {
2015-01-04 02:59:56 +00:00
ringbuffer - > packetsAvail = 0 ;
2013-06-01 17:29:59 +00:00
} else {
2015-01-04 02:59:56 +00:00
ringbuffer - > packetsAvail = ringbuffer - > packets - ( ringbuffer - > dataUpperBound - ringbuffer - > data ) / ringbuffer - > packetSize ;
2013-06-01 17:29:59 +00:00
}
2014-03-02 01:19:55 +00:00
ringbuffer - > mpeg = mpegAddr ;
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-03-02 01:19:55 +00:00
if ( ringbuffer . IsValid ( ) ) {
2013-07-23 12:26:33 +00:00
Memory : : Write_U32 ( ringbufferAddr , mpegHandle + 16 ) ;
2014-03-02 01:19:55 +00:00
Memory : : Write_U32 ( ringbuffer - > dataUpperBound , mpegHandle + 20 ) ;
2013-07-23 12:26:33 +00:00
}
2012-12-24 18:31:33 +00:00
MpegContext * ctx = new MpegContext ;
2014-03-30 20:06:42 +00:00
if ( mpegMap . find ( mpegHandle ) ! = mpegMap . end ( ) ) {
WARN_LOG_REPORT ( HLE , " Replacing existing mpeg context at %08x " , mpegAddr ) ;
// Otherwise, it would leak.
delete mpegMap [ mpegHandle ] ;
}
2012-12-24 18:31:33 +00:00
mpegMap [ mpegHandle ] = ctx ;
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
}
2014-12-08 09:40:08 +00:00
static 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
2017-02-07 21:18:22 +00:00
return hleDelayResult ( 0 , " mpeg delete " , 40000 ) ;
2012-11-13 17:05:26 +00:00
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-12-08 09:40:08 +00:00
static 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 ;
2014-06-21 16:27:39 +00:00
// TODO: Probably incorrect?
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 ;
2014-06-21 16:27:39 +00:00
// TODO: Probably incorrect?
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 ;
2015-04-08 18:33:13 +00:00
info . sid = sid ;
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 ;
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-04-04 21:01:25 +00:00
// check the existence of pmp media context
2014-12-08 09:40:08 +00:00
static bool isContextExist ( u32 ctxAddr ) {
2014-12-25 03:20:21 +00:00
for ( auto it = pmp_ContextList . begin ( ) ; it ! = pmp_ContextList . end ( ) ; + + it ) {
2014-04-08 02:17:32 +00:00
if ( * it = = ctxAddr ) {
2014-04-04 21:01:25 +00:00
return true ;
2014-04-01 02:58:56 +00:00
}
2014-04-04 21:01:25 +00:00
}
return false ;
}
2014-04-01 02:58:56 +00:00
2014-04-04 21:01:25 +00:00
// Initialize Pmp video parameters and decoder.
2014-12-08 09:40:08 +00:00
static bool InitPmp ( MpegContext * ctx ) {
2014-04-04 21:01:25 +00:00
# ifdef USE_FFMPEG
InitFFmpeg ( ) ;
auto mediaengine = ctx - > mediaengine ;
mediaengine - > m_isVideoEnd = false ;
mediaengine - > m_firstTimeStamp = 0 ;
mediaengine - > m_lastTimeStamp = 0 ;
ctx - > mpegFirstTimestamp = 0 ;
ctx - > mpegLastTimestamp = 0 ;
2014-04-07 22:57:25 +00:00
// wanted output pixel format
2014-04-08 02:22:53 +00:00
// reference values for pix_fmt:
2014-04-07 22:57:25 +00:00
// GE_CMODE_16BIT_BGR5650 <--> AV_PIX_FMT_BGR565LE
// GE_CMODE_16BIT_ABGR5551 <--> AV_PIX_FMT_BGR555LE;
// GE_CMODE_16BIT_ABGR4444 <--> AV_PIX_FMT_BGR444LE;
// GE_CMODE_32BIT_ABGR8888 <--> AV_PIX_FMT_RGBA;
2015-09-12 08:45:03 +00:00
pmp_want_pix_fmt = AV_PIX_FMT_RGBA ;
2014-04-04 21:01:25 +00:00
// Create H264 video codec
2015-09-12 08:45:03 +00:00
AVCodec * pmp_Codec = avcodec_find_decoder ( AV_CODEC_ID_H264 ) ;
2014-04-04 21:01:25 +00:00
if ( pmp_Codec = = NULL ) {
ERROR_LOG ( ME , " Can not find H264 codec, please update ffmpeg " ) ;
return false ;
}
// Create CodecContext
AVCodecContext * pmp_CodecCtx = avcodec_alloc_context3 ( pmp_Codec ) ;
if ( pmp_CodecCtx = = NULL ) {
ERROR_LOG ( ME , " Can not allocate pmp Codec Context " ) ;
return false ;
}
// each pmp video context is corresponding to one pmp video codec
mediaengine - > m_pCodecCtxs [ 0 ] = pmp_CodecCtx ;
// initialize H264 video parameters
// set pmp video size. Better to get from pmp file directly if possible. Any idea?
pmp_CodecCtx - > width = 480 ;
pmp_CodecCtx - > height = 272 ;
mediaengine - > m_desHeight = pmp_CodecCtx - > height ;
mediaengine - > m_desWidth = pmp_CodecCtx - > width ;
// Open pmp video codec
if ( avcodec_open2 ( pmp_CodecCtx , pmp_Codec , NULL ) < 0 ) {
ERROR_LOG ( ME , " Can not open pmp video codec " ) ;
return false ;
}
// initialize ctx->mediaengine->m_pFrame and ctx->mediaengine->m_pFrameRGB
2014-04-07 22:57:25 +00:00
if ( ! mediaengine - > m_pFrame ) {
2014-06-10 13:06:00 +00:00
mediaengine - > m_pFrame = av_frame_alloc ( ) ;
2014-04-04 21:01:25 +00:00
}
2014-04-07 22:57:25 +00:00
if ( ! mediaengine - > m_pFrameRGB ) {
2014-06-10 13:06:00 +00:00
mediaengine - > m_pFrameRGB = av_frame_alloc ( ) ;
2014-04-04 21:01:25 +00:00
}
// get RGBA picture buffer
2016-05-28 17:11:53 +00:00
# if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
mediaengine - > m_bufSize = av_image_get_buffer_size ( pmp_want_pix_fmt , pmp_CodecCtx - > width , pmp_CodecCtx - > height , 1 ) ;
# else
2014-04-04 21:01:25 +00:00
mediaengine - > m_bufSize = avpicture_get_size ( pmp_want_pix_fmt , pmp_CodecCtx - > width , pmp_CodecCtx - > height ) ;
2016-05-28 17:11:53 +00:00
# endif
2014-04-04 21:01:25 +00:00
mediaengine - > m_buffer = ( u8 * ) av_malloc ( mediaengine - > m_bufSize ) ;
2014-04-01 02:58:56 +00:00
return true ;
2014-04-04 21:01:25 +00:00
# else
// we can not play pmp video without ffmpeg
return false ;
# endif
2014-04-01 02:58:56 +00:00
}
2014-04-07 22:57:25 +00:00
// This class H264Frames is used for collecting small pieces of frames into larger frames for ffmpeg to decode
// Basically, this will avoid incomplete frame decoding issue and improve much better the video quality.
2014-04-07 16:26:11 +00:00
class H264Frames {
public :
int size ;
u8 * stream ;
H264Frames ( ) : size ( 0 ) , stream ( NULL ) { } ;
H264Frames ( u8 * str , int sz ) : size ( sz ) {
stream = new u8 [ size ] ;
memcpy ( stream , str , size ) ;
} ;
H264Frames ( H264Frames * frame ) {
size = frame - > size ;
stream = new u8 [ size ] ;
memcpy ( stream , frame - > stream , size ) ;
} ;
~ H264Frames ( ) {
size = 0 ;
if ( stream ) {
delete [ ] stream ;
stream = NULL ;
}
} ;
void add ( H264Frames * p ) {
add ( p - > stream , p - > size ) ;
} ;
void add ( u8 * str , int sz ) {
int newsize = size + sz ;
2014-04-07 22:57:25 +00:00
u8 * newstream = new u8 [ newsize ] ;
2014-04-07 16:26:11 +00:00
// join two streams
memcpy ( newstream , stream , size ) ;
memcpy ( newstream + size , str , sz ) ;
// delete old stream
2014-12-03 21:48:58 +00:00
delete [ ] stream ;
2014-04-07 16:26:11 +00:00
// replace with new stream
stream = newstream ;
size = newsize ;
} ;
void remove ( int pos ) {
// remove stream from begining to pos
if ( pos = = 0 ) {
// nothing to remove
}
else if ( pos > = size ) {
// we remove all
size = 0 ;
if ( stream ) {
delete [ ] stream ;
stream = NULL ;
}
}
else {
// we remove the front part
size - = pos ;
2014-04-07 22:57:25 +00:00
u8 * str = new u8 [ size ] ;
2014-04-07 16:26:11 +00:00
memcpy ( str , stream + pos , size ) ;
delete [ ] stream ;
stream = str ;
}
} ;
# ifndef USE_FFMPEG
# define FF_INPUT_BUFFER_PADDING_SIZE 16
# endif
void addpadding ( ) {
2014-04-07 22:57:25 +00:00
u8 * str = new u8 [ size + FF_INPUT_BUFFER_PADDING_SIZE ] ;
2014-04-07 16:26:11 +00:00
memcpy ( str , stream , size ) ;
memset ( str + size , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
size + = FF_INPUT_BUFFER_PADDING_SIZE ;
delete [ ] stream ;
stream = str ;
}
} ;
// collect pmp video frames
2014-04-07 22:57:25 +00:00
static H264Frames * pmpframes ;
2014-04-07 16:26:11 +00:00
2014-04-04 21:01:25 +00:00
// decode pmp video to RGBA format
2014-12-08 09:40:08 +00:00
static bool decodePmpVideo ( PSPPointer < SceMpegRingBuffer > ringbuffer , u32 pmpctxAddr ) {
2017-02-24 17:59:41 +00:00
# ifdef USE_FFMPEG
2014-04-07 22:57:25 +00:00
// the current video is pmp iff pmp_videoSource is a valid addresse
MpegContext * ctx = getMpegCtx ( pmpctxAddr ) ;
2014-04-04 21:01:25 +00:00
if ( Memory : : IsValidAddress ( pmp_videoSource ) ) {
// We should initialize pmp codec for each pmp context
2014-04-07 03:16:45 +00:00
if ( isContextExist ( pmpctxAddr ) = = false ) {
2014-04-07 22:57:25 +00:00
bool ret = InitPmp ( ctx ) ;
2014-04-04 21:01:25 +00:00
if ( ! ret ) {
ERROR_LOG ( ME , " Pmp video initialization failed " ) ;
return false ;
}
// add the initialized context into ContextList
2014-04-07 03:16:45 +00:00
pmp_ContextList . push_front ( pmpctxAddr ) ;
2014-04-01 02:58:56 +00:00
}
2014-04-04 21:01:25 +00:00
ringbuffer - > packetsRead = pmp_nBlocks ;
2014-04-07 22:57:25 +00:00
MediaEngine * mediaengine = ctx - > mediaengine ;
AVFrame * pFrame = mediaengine - > m_pFrame ;
AVFrame * pFrameRGB = mediaengine - > m_pFrameRGB ;
2014-04-04 21:01:25 +00:00
auto pCodecCtx = mediaengine - > m_pCodecCtxs [ 0 ] ;
2014-04-02 05:20:52 +00:00
2014-04-07 22:57:25 +00:00
// pmpframes could be destroied when close a video to load another one
if ( ! pmpframes )
pmpframes = new H264Frames ;
2014-04-07 16:26:11 +00:00
// joint all blocks into H264Frames
2014-04-02 05:20:52 +00:00
SceMpegLLI lli ;
2014-04-04 21:01:25 +00:00
for ( int i = 0 ; i < pmp_nBlocks ; i + + ) {
2015-09-21 18:16:03 +00:00
Memory : : ReadStructUnchecked ( pmp_videoSource , & lli ) ;
2014-04-07 16:26:11 +00:00
// add source block into pmpframes
pmpframes - > add ( Memory : : GetPointer ( lli . pSrc ) , lli . iSize ) ;
// get next block
pmp_videoSource + = sizeof ( SceMpegLLI ) ;
}
2014-04-02 05:20:52 +00:00
2014-04-07 16:26:11 +00:00
pmpframes - > addpadding ( ) ;
// initialize packet
AVPacket packet ;
av_new_packet ( & packet , pCodecCtx - > width * pCodecCtx - > height ) ;
// set packet to source block
packet . data = pmpframes - > stream ;
packet . size = pmpframes - > size ;
// reuse pFrame and pFrameRGB
int got_picture = 0 ;
av_frame_unref ( pFrame ) ;
av_frame_unref ( pFrameRGB ) ;
// hook pFrameRGB output to buffer
2016-05-28 17:11:53 +00:00
# if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
av_image_fill_arrays ( pFrameRGB - > data , pFrameRGB - > linesize , mediaengine - > m_buffer , pmp_want_pix_fmt , pCodecCtx - > width , pCodecCtx - > height , 1 ) ;
# else
2014-04-07 16:26:11 +00:00
avpicture_fill ( ( AVPicture * ) pFrameRGB , mediaengine - > m_buffer , pmp_want_pix_fmt , pCodecCtx - > width , pCodecCtx - > height ) ;
2016-05-28 17:11:53 +00:00
# endif
2014-04-07 16:26:11 +00:00
// decode video frame
2014-04-07 22:57:25 +00:00
int len = avcodec_decode_video2 ( pCodecCtx , pFrame , & got_picture , & packet ) ;
2014-04-07 16:26:11 +00:00
DEBUG_LOG ( ME , " got_picture %d " , got_picture ) ;
if ( got_picture ) {
SwsContext * img_convert_ctx = NULL ;
img_convert_ctx = sws_getContext (
pCodecCtx - > width ,
pCodecCtx - > height ,
pCodecCtx - > pix_fmt ,
pCodecCtx - > width ,
pCodecCtx - > height ,
pmp_want_pix_fmt ,
SWS_BILINEAR ,
NULL , NULL , NULL ) ;
if ( ! img_convert_ctx ) {
ERROR_LOG ( ME , " Cannot initialize sws conversion context " ) ;
return false ;
2014-03-31 22:27:39 +00:00
}
2014-04-07 16:26:11 +00:00
// Convert to RGBA
int swsRet = sws_scale ( img_convert_ctx , ( const uint8_t * const * ) pFrame - > data ,
pFrame - > linesize , 0 , pCodecCtx - > height , pFrameRGB - > data , pFrameRGB - > linesize ) ;
if ( swsRet < 0 ) {
ERROR_LOG ( ME , " sws_scale: Error while converting %d " , swsRet ) ;
return false ;
}
// free sws context
sws_freeContext ( img_convert_ctx ) ;
// update timestamp
if ( av_frame_get_best_effort_timestamp ( mediaengine - > m_pFrame ) ! = AV_NOPTS_VALUE )
mediaengine - > m_videopts = av_frame_get_best_effort_timestamp ( mediaengine - > m_pFrame ) + av_frame_get_pkt_duration ( mediaengine - > m_pFrame ) - mediaengine - > m_firstTimeStamp ;
else
mediaengine - > m_videopts + = av_frame_get_pkt_duration ( mediaengine - > m_pFrame ) ;
// push the decoded frame into pmp_queue
pmp_queue . push_back ( pFrameRGB ) ;
// write frame into ppm file
// SaveFrame(pNewFrameRGB, pCodecCtx->width, pCodecCtx->height);
2014-03-31 22:27:39 +00:00
}
2014-04-07 16:26:11 +00:00
// free some pointers
2016-05-28 17:11:53 +00:00
# if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
av_packet_unref ( & packet ) ;
# else
2014-04-07 16:26:11 +00:00
av_free_packet ( & packet ) ;
2016-05-28 17:11:53 +00:00
# endif
2014-04-07 16:26:11 +00:00
pmpframes - > ~ H264Frames ( ) ;
2014-04-04 21:01:25 +00:00
// must reset pmp_VideoSource address to zero after decoding.
pmp_videoSource = 0 ;
2014-04-01 02:58:56 +00:00
return true ;
2014-03-31 22:27:39 +00:00
}
2014-04-02 05:20:52 +00:00
// not a pmp video, return false
return false ;
2017-02-24 17:59:41 +00:00
# else
return false ;
# endif
2014-03-31 22:27:39 +00:00
}
2014-04-04 21:01:25 +00:00
void __VideoPmpInit ( ) {
pmp_oldStateLoaded = false ;
2014-04-07 22:57:25 +00:00
pmpframes = new H264Frames ( ) ;
2014-04-04 21:01:25 +00:00
}
void __VideoPmpShutdown ( ) {
# ifdef USE_FFMPEG
// We need to empty pmp_queue to not leak memory.
2014-12-25 03:20:21 +00:00
for ( auto it = pmp_queue . begin ( ) ; it ! = pmp_queue . end ( ) ; + + it ) {
2014-04-04 21:01:25 +00:00
av_free ( * it ) ;
}
pmp_queue . clear ( ) ;
pmp_ContextList . clear ( ) ;
2014-04-07 22:57:25 +00:00
delete pmpframes ;
pmpframes = NULL ;
2014-04-04 21:01:25 +00:00
# endif
}
void __VideoPmpDoState ( PointerWrap & p ) {
auto s = p . Section ( " PMPVideo " , 0 , 1 ) ;
if ( ! s ) {
if ( p . mode = = PointerWrap : : MODE_READ )
pmp_oldStateLoaded = true ;
return ;
}
p . Do ( pmp_videoSource ) ;
p . Do ( pmp_nBlocks ) ;
if ( p . mode = = PointerWrap : : MODE_READ ) {
// for loadstate, we will reinitialize the pmp codec
__VideoPmpShutdown ( ) ;
}
}
2014-12-08 09:40:08 +00:00
static 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 ) ;
2014-03-31 22:27:39 +00:00
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ! ringbuffer . IsValid ( ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( ME , " Bogus mpegringbufferaddr " ) ;
2013-06-10 22:51:10 +00:00
return - 1 ;
}
2014-03-31 22:27:39 +00:00
u32 buffer = Memory : : Read_U32 ( bufferAddr ) ;
u32 init = Memory : : Read_U32 ( initAddr ) ;
2014-04-04 21:10:33 +00:00
DEBUG_LOG ( ME , " video: bufferAddr = %08x, *buffer = %08x, *init = %08x " , bufferAddr , buffer , init ) ;
2014-03-31 22:27:39 +00:00
2014-04-04 21:01:25 +00:00
// check and decode pmp video
2014-03-31 22:27:39 +00:00
bool ispmp = false ;
2014-04-07 03:16:45 +00:00
if ( decodePmpVideo ( ringbuffer , mpeg ) ) {
2014-04-04 21:01:25 +00:00
DEBUG_LOG ( ME , " Using ffmpeg to decode pmp video " ) ;
2014-03-31 22:27:39 +00:00
ispmp = true ;
}
2012-11-13 17:05:26 +00:00
2014-03-02 01:19:55 +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
}
2016-06-05 01:02:55 +00:00
s32 beforeAvail = ringbuffer - > packets - ctx - > mediaengine - > getRemainSize ( ) / 2048 ;
2014-06-21 16:27:39 +00:00
// We stored the video stream id here in sceMpegGetAvcAu().
ctx - > mediaengine - > setVideoStream ( avcAu . esBuffer ) ;
2014-04-04 21:01:25 +00:00
if ( ispmp ) {
2017-02-24 17:59:41 +00:00
# ifdef USE_FFMPEG
2014-04-04 21:01:25 +00:00
while ( pmp_queue . size ( ) ! = 0 ) {
// playing all pmp_queue frames
ctx - > mediaengine - > m_pFrameRGB = pmp_queue . front ( ) ;
int bufferSize = ctx - > mediaengine - > writeVideoImage ( buffer , frameWidth , ctx - > videoPixelMode ) ;
2016-01-17 20:43:13 +00:00
gpu - > NotifyVideoUpload ( buffer , bufferSize , frameWidth , ctx - > videoPixelMode ) ;
2014-04-04 21:01:25 +00:00
ctx - > avc . avcFrameStatus = 1 ;
ctx - > videoFrameCount + + ;
// free front frame
hleDelayResult ( 0 , " pmp video decode " , 30 ) ;
pmp_queue . pop_front ( ) ;
}
2017-02-24 17:59:41 +00:00
# endif
2014-04-04 21:01:25 +00:00
}
else if ( ctx - > mediaengine - > stepVideo ( ctx - > videoPixelMode ) ) {
2013-12-11 16:21:01 +00:00
int bufferSize = ctx - > mediaengine - > writeVideoImage ( buffer , frameWidth , ctx - > videoPixelMode ) ;
2016-01-17 20:43:13 +00:00
gpu - > NotifyVideoUpload ( buffer , bufferSize , frameWidth , ctx - > videoPixelMode ) ;
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
}
2016-06-05 01:02:55 +00:00
s32 afterAvail = ringbuffer - > packets - ctx - > mediaengine - > getRemainSize ( ) / 2048 ;
// Don't actually reset avail, we only change it by what was decoded.
// Garbage frames can cause this to be incorrect, but some games expect that.
if ( mpegLibVersion < = 0x0103 ) {
ringbuffer - > packetsAvail + = afterAvail - beforeAvail ;
} else {
ringbuffer - > packetsAvail = afterAvail ;
}
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
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
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcDecodeStop ( u32 mpeg , u32 frameWidth , u32 bufferAddr , u32 statusAddr )
2012-11-12 19:53:16 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static 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
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-12-08 09:40:08 +00:00
static 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
2014-12-08 09:40:08 +00:00
static 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 ) ;
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ! ringbuffer . IsValid ( ) ) {
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
2014-03-02 01:19:55 +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
}
2016-06-05 01:02:55 +00:00
s32 beforeAvail = ringbuffer - > packets - ctx - > mediaengine - > getRemainSize ( ) / 2048 ;
2014-06-21 16:27:39 +00:00
// We stored the video stream id here in sceMpegGetAvcAu().
ctx - > mediaengine - > setVideoStream ( avcAu . esBuffer ) ;
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 + + ;
2016-06-05 01:02:55 +00:00
} else {
2013-06-11 06:18:08 +00:00
ctx - > avc . avcFrameStatus = 0 ;
2013-02-02 09:51:41 +00:00
}
2016-06-05 01:02:55 +00:00
s32 afterAvail = ringbuffer - > packets - ctx - > mediaengine - > getRemainSize ( ) / 2048 ;
// Don't actually reset avail, we only change it by what was decoded.
// Garbage frames can cause this to be incorrect, but some games expect that.
if ( mpegLibVersion < = 0x0103 ) {
ringbuffer - > packetsAvail + = afterAvail - beforeAvail ;
} else {
ringbuffer - > packetsAvail = afterAvail ;
}
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 ) ;
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
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-12-08 09:40:08 +00:00
static 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
2014-02-05 01:10:27 +00:00
SceMpegAu sceAu ;
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.
2016-01-17 08:30:18 +00:00
// Default to 0, since we stuff the stream id in here. Technically, we shouldn't.
// TODO: Do something better to track the AU data. This used to be bufferAddr.
sceAu . esBuffer = 0 ;
2014-02-05 01:10:27 +00:00
sceAu . esSize = MPEG_AVC_ES_SIZE ;
sceAu . dts = 0 ;
sceAu . pts = 0 ;
2012-11-13 17:05:26 +00:00
2014-02-05 01:10:27 +00:00
sceAu . write ( auPointer ) ;
2012-11-13 17:05:26 +00:00
} else {
// This esbuffer has been left as Atrac.
2016-01-17 08:30:18 +00:00
// Default to 0, since we stuff the stream id in here. Technically, we shouldn't.
// TODO: Do something better to track the AU data. This used to be bufferAddr.
sceAu . esBuffer = 0 ;
2014-02-05 01:10:27 +00:00
sceAu . esSize = MPEG_ATRAC_ES_SIZE ;
sceAu . pts = 0 ;
sceAu . dts = UNKNOWN_TIMESTAMP ;
2012-11-13 17:05:26 +00:00
2014-02-05 01:10:27 +00:00
sceAu . write ( auPointer ) ;
2012-11-13 17:05:26 +00:00
}
return 0 ;
2012-11-12 19:53:16 +00:00
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-07-27 15:40:46 +00:00
ctx - > mpegRingbufferAddr = ringbufferAddr ;
2013-06-22 15:36:31 +00:00
hleEatCycles ( 2020 ) ;
2014-06-13 07:30:21 +00:00
hleReSchedule ( " mpeg ringbuffer avail " ) ;
2015-01-04 02:59:56 +00:00
static int lastAvail = 0 ;
if ( lastAvail ! = ringbuffer - > packetsAvail ) {
DEBUG_LOG ( ME , " %i=sceMpegRingbufferAvailableSize(%08x) " , ringbuffer - > packets - ringbuffer - > packetsAvail , ringbufferAddr ) ;
lastAvail = ringbuffer - > packetsAvail ;
2013-12-14 20:59:50 +00:00
} else {
2015-01-04 02:59:56 +00:00
VERBOSE_LOG ( ME , " %i=sceMpegRingbufferAvailableSize(%08x) " , ringbuffer - > packets - ringbuffer - > packetsAvail , ringbufferAddr ) ;
2013-12-14 20:59:50 +00:00
}
2015-01-04 02:59:56 +00:00
return ringbuffer - > packets - ringbuffer - > packetsAvail ;
2012-11-01 15:19:01 +00:00
}
2013-01-06 18:54:33 +00:00
void PostPutAction : : run ( MipsCall & call ) {
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ringAddr_ ) ;
2012-11-13 17:05:26 +00:00
2014-03-02 01:19:55 +00:00
MpegContext * ctx = getMpegCtx ( ringbuffer - > mpeg ) ;
2016-06-05 00:34:49 +00:00
int writeOffset = ringbuffer - > packetsWritePos % ( s32 ) ringbuffer - > packets ;
const u8 * data = Memory : : GetPointer ( ringbuffer - > data + writeOffset * 2048 ) ;
2012-11-13 17:05:26 +00:00
2014-03-04 16:21:55 +00:00
int packetsAdded = currentMIPS - > r [ MIPS_REG_V0 ] ;
2016-06-05 00:34:49 +00:00
2016-06-05 01:01:47 +00:00
// It seems validation is done only by older mpeg libs.
if ( mpegLibVersion < 0x0105 & & packetsAdded > 0 ) {
// TODO: Faster / less wasteful validation.
2017-02-20 10:12:39 +00:00
std : : unique_ptr < MpegDemux > demuxer ( new MpegDemux ( packetsAdded * 2048 , 0 ) ) ;
2016-06-05 01:01:47 +00:00
int readOffset = ringbuffer - > packetsRead % ( s32 ) ringbuffer - > packets ;
const u8 * buf = Memory : : GetPointer ( ringbuffer - > data + readOffset * 2048 ) ;
bool invalid = false ;
for ( int i = 0 ; i < packetsAdded ; + + i ) {
demuxer - > addStreamData ( buf , 2048 ) ;
buf + = 2048 ;
if ( ! demuxer - > demux ( 0xFFFF ) ) {
invalid = true ;
}
}
if ( invalid ) {
// Bail out early - don't accept any of the packets, even the good ones.
ERROR_LOG_REPORT ( ME , " sceMpegRingbufferPut(): invalid mpeg data " ) ;
call . setReturnValue ( ERROR_MPEG_INVALID_VALUE ) ;
if ( mpegLibVersion < = 0x0103 ) {
// Act like they were actually added, but don't increment read pos.
ringbuffer - > packetsWritePos + = packetsAdded ;
ringbuffer - > packetsAvail + = packetsAdded ;
}
return ;
}
}
2014-03-02 01:19:55 +00:00
if ( ringbuffer - > packetsRead = = 0 & & ctx - > mediaengine & & packetsAdded > 0 ) {
2013-07-01 17:04:19 +00:00
// init mediaEngine
2013-07-01 17:26:31 +00:00
AnalyzeMpeg ( ctx - > mpegheader , ctx ) ;
2014-03-02 01:19:55 +00:00
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 ) {
2015-01-04 02:59:56 +00:00
if ( packetsAdded > ringbuffer - > packets - ringbuffer - > packetsAvail ) {
WARN_LOG ( ME , " sceMpegRingbufferPut clamping packetsAdded old=%i new=%i " , packetsAdded , ringbuffer - > packets - ringbuffer - > packetsAvail ) ;
packetsAdded = ringbuffer - > packets - ringbuffer - > packetsAvail ;
2012-11-13 17:05:26 +00:00
}
2016-06-05 00:34:49 +00:00
int actuallyAdded = ctx - > mediaengine = = NULL ? 8 : ctx - > mediaengine - > addStreamData ( 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
}
2014-03-02 01:19:55 +00:00
ringbuffer - > packetsRead + = packetsAdded ;
2016-06-05 00:34:49 +00:00
ringbuffer - > packetsWritePos + = packetsAdded ;
2015-01-04 02:59:56 +00:00
ringbuffer - > packetsAvail + = packetsAdded ;
2012-11-13 17:05:26 +00:00
}
2014-03-02 01:19: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
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 ?
2016-06-04 21:17:29 +00:00
static u32 sceMpegRingbufferPut ( u32 ringbufferAddr , int numPackets , int available )
2012-11-01 15:19:01 +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 ) {
2014-07-12 16:56:03 +00:00
DEBUG_LOG ( ME , " sceMpegRingbufferPut(%08x, %i, %i): no packets to enqueue " , ringbufferAddr , numPackets , available ) ;
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
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ringbufferAddr ) ;
if ( ! ringbuffer . IsValid ( ) ) {
// Would have crashed before, TODO test behavior.
ERROR_LOG_REPORT ( ME , " sceMpegRingbufferPut(%08x, %i, %i): invalid ringbuffer address " , ringbufferAddr , numPackets , available ) ;
return - 1 ;
}
2012-11-13 17:05:26 +00:00
2014-03-02 01:19:55 +00:00
MpegContext * ctx = getMpegCtx ( ringbuffer - > mpeg ) ;
2012-12-24 18:04:05 +00:00
if ( ! ctx ) {
2014-03-02 01:19: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
2014-03-02 01:19:55 +00:00
if ( ringbuffer - > callback_addr ! = 0 ) {
2014-07-12 16:56:03 +00:00
DEBUG_LOG ( ME , " sceMpegRingbufferPut(%08x, %i, %i) " , ringbufferAddr , numPackets , available ) ;
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.
2016-06-05 00:34:49 +00:00
int writeOffset = ringbuffer - > packetsWritePos % ( s32 ) ringbuffer - > packets ;
u32 packetsThisRound = std : : min ( numPackets , ( s32 ) ringbuffer - > packets - writeOffset ) ;
u32 args [ 3 ] = { ( u32 ) ringbuffer - > data + ( u32 ) writeOffset * 2048 , packetsThisRound , ( u32 ) ringbuffer - > callback_args } ;
2014-03-02 01:19:55 +00:00
__KernelDirectMipsCall ( ringbuffer - > callback_addr , action , args , 3 , false ) ;
2012-11-13 17:05:26 +00:00
} else {
2014-03-02 01:19:55 +00:00
ERROR_LOG_REPORT ( 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
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ! ringbuffer . IsValid ( ) ) {
// Would have crashed before, TODO test behavior.
ERROR_LOG_REPORT ( ME , " sceMpegGetAvcAu(%08x, %08x, %08x, %08x): invalid ringbuffer address " , mpeg , streamId , auAddr , attrAddr ) ;
return - 1 ;
}
2012-11-13 17:05:26 +00:00
2014-02-04 14:55:41 +00:00
SceMpegAu avcAu ;
avcAu . read ( auAddr ) ;
2012-11-13 17:05:26 +00:00
2015-01-04 02:59:56 +00:00
if ( ringbuffer - > packetsRead = = 0 | | ringbuffer - > packetsAvail = = 0 ) {
2014-02-01 15:56:34 +00:00
DEBUG_LOG ( ME , " ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x) " , mpeg , streamId , auAddr , attrAddr ) ;
2014-02-04 14:55:41 +00:00
avcAu . pts = - 1 ;
avcAu . dts = - 1 ;
avcAu . 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-06-21 16:27:39 +00:00
if ( streamInfo = = ctx - > streamMap . end ( ) ) {
2014-02-01 16:43:40 +00:00
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 ) {
2014-02-04 14:55:41 +00:00
avcAu . pts = 0 ;
2013-04-01 14:56:43 +00:00
streamInfo - > second . needsReset = false ;
}
2014-06-21 16:27:39 +00:00
// esBuffer is the memory where this au data goes. We don't write the data to memory.
// Instead, let's abuse it to keep track of the stream number.
avcAu . esBuffer = streamInfo - > second . num ;
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
2014-02-04 14:55:41 +00:00
avcAu . pts = ctx - > mediaengine - > getVideoTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
avcAu . dts = avcAu . pts - videoTimestampStep ;
2013-06-04 12:25:03 +00:00
if ( ctx - > mediaengine - > IsVideoEnd ( ) ) {
2014-02-04 14:55:41 +00:00
INFO_LOG ( ME , " video end reach. pts: %i dts: %i " , ( int ) avcAu . pts , ( int ) ctx - > mediaengine - > getLastTimeStamp ( ) ) ;
2015-01-04 02:59:56 +00:00
ringbuffer - > packetsAvail = 0 ;
2013-06-01 17:29:59 +00:00
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.
2014-02-04 14:55:41 +00:00
avcAu . write ( auAddr ) ;
2013-01-07 03:22:52 +00:00
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
}
2014-12-08 09:40:08 +00:00
static 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(...) " ) ;
2014-04-07 17:52:33 +00:00
__VideoPmpShutdown ( ) ;
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
}
2016-06-04 21:05:34 +00:00
static u32 sceMpegQueryMemSize ( ) {
return hleLogSuccessX ( ME , MpegRequiredMem ( ) ) ;
2012-11-10 09:15:11 +00:00
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ! ringbuffer . IsValid ( ) ) {
// Would have crashed before, TODO test behavior.
WARN_LOG ( ME , " sceMpegGetAtracAu(%08x, %08x, %08x, %08x): invalid ringbuffer address " , mpeg , streamId , auAddr , attrAddr ) ;
return - 1 ;
}
2012-11-13 17:05:26 +00:00
2014-02-04 14:55:41 +00:00
SceMpegAu atracAu ;
atracAu . 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 ) {
2014-02-04 14:55:41 +00:00
atracAu . pts = 0 ;
2013-04-01 14:56:43 +00:00
streamInfo - > second . needsReset = false ;
}
2014-06-21 16:27:39 +00:00
if ( streamInfo = = ctx - > streamMap . end ( ) ) {
2014-02-01 16:43:40 +00:00
WARN_LOG_REPORT ( ME , " sceMpegGetAtracAu: invalid audio stream %08x " , streamId ) ;
2014-09-01 04:13:51 +00:00
// TODO: Why was this changed to not return an error?
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.
2015-01-04 02:59:56 +00:00
if ( ringbuffer - > packetsAvail = = 0 ) {
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
}
2014-06-21 16:27:39 +00:00
// esBuffer is the memory where this au data goes. We don't write the data to memory.
// Instead, let's abuse it to keep track of the stream number.
2014-09-01 04:13:51 +00:00
if ( streamInfo ! = ctx - > streamMap . end ( ) ) {
atracAu . esBuffer = streamInfo - > second . num ;
}
2014-06-21 16:27:39 +00:00
2013-06-01 17:29:59 +00:00
int result = 0 ;
2014-02-04 14:55:41 +00:00
atracAu . pts = ctx - > mediaengine - > getAudioTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2014-02-09 13:48:26 +00:00
2013-06-04 12:25:03 +00:00
if ( ctx - > mediaengine - > IsVideoEnd ( ) ) {
2014-02-04 14:55:41 +00:00
INFO_LOG ( ME , " video end reach. pts: %i dts: %i " , ( int ) atracAu . pts , ( int ) ctx - > mediaengine - > getLastTimeStamp ( ) ) ;
2015-01-04 02:59:56 +00:00
ringbuffer - > packetsAvail = 0 ;
2016-09-25 00:54:40 +00:00
// TODO: Is this correct?
if ( ! ctx - > mediaengine - > IsNoAudioData ( ) ) {
WARN_LOG_REPORT ( ME , " Video end without audio end, potentially skipping some audio? " ) ;
}
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
2014-02-10 01:31:54 +00:00
if ( ctx - > atracRegistered & & ctx - > mediaengine - > IsNoAudioData ( ) & & ! ctx - > endOfAudioReached ) {
2014-02-09 13:48:26 +00:00
WARN_LOG ( ME , " Audio end reach. pts: %i dts: %i " , ( int ) atracAu . pts , ( int ) ctx - > mediaengine - > getLastTimeStamp ( ) ) ;
ctx - > endOfAudioReached = true ;
2016-09-25 00:54:40 +00:00
}
if ( ctx - > mediaengine - > IsNoAudioData ( ) ) {
2014-02-01 15:56:34 +00:00
result = ERROR_MPEG_NO_DATA ;
2014-01-10 15:41:32 +00:00
}
2014-02-04 14:55:41 +00:00
atracAu . write ( auAddr ) ;
2013-06-01 17:29:59 +00:00
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
}
2014-12-08 09:40:08 +00:00
static 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
}
2015-03-01 17:26:08 +00:00
ERROR_LOG ( ME , " sceMpegQueryPcmEsSize(%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
2014-12-08 09:40:08 +00:00
static 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 ) ;
2015-03-01 17:26:53 +00:00
return ERROR_MPEG_INVALID_VALUE ;
}
if ( mode ! = MPEG_AU_MODE_DECODE & & mode ! = MPEG_AU_MODE_SKIP ) {
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): bad mode " , mpeg , streamUid , mode ) ;
return ERROR_MPEG_INVALID_VALUE ;
2013-01-08 09:04:51 +00:00
}
2015-03-01 17:26:53 +00:00
auto stream = ctx - > streamMap . find ( streamUid ) ;
if ( stream = = ctx - > streamMap . end ( ) ) {
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID " , mpeg , streamUid , mode ) ;
return ERROR_MPEG_INVALID_VALUE ;
} else {
StreamInfo & info = stream - > second ;
DEBUG_LOG ( ME , " UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): changing type=%d " , mpeg , streamUid , mode , info . type ) ;
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 :
2015-03-01 17:26:53 +00:00
ERROR_LOG ( ME , " UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID " , mpeg , streamUid , mode ) ;
2013-01-08 09:04:51 +00:00
break ;
}
}
2013-01-08 02:03:48 +00:00
return 0 ;
2012-11-10 09:15:11 +00:00
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegChangeGetAvcAuMode ( u32 mpeg , u32 stream_addr , int mode )
2013-01-08 08:16:18 +00:00
{
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 ;
}
2015-02-28 19:15:02 +00:00
ERROR_LOG_REPORT_ONCE ( mpegChangeAvcAu , 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
}
2014-12-08 09:40:08 +00:00
static 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 ;
}
2015-02-28 22:52:45 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ! ringbuffer . IsValid ( ) ) {
// Would have crashed before, TODO test behavior
WARN_LOG ( ME , " sceMpegGetPcmAu(%08x, %08x, %08x, %08x): invalid ringbuffer address " , mpeg , streamUid , auAddr , attrAddr ) ;
return - 1 ;
}
if ( ! Memory : : IsValidAddress ( streamUid ) ) {
WARN_LOG ( ME , " sceMpegGetPcmAu(%08x, %08x, %08x, %08x): didn't get a fake stream " , mpeg , streamUid , auAddr , attrAddr ) ;
return ERROR_MPEG_INVALID_ADDR ;
}
SceMpegAu atracAu ;
atracAu . read ( auAddr ) ;
auto streamInfo = ctx - > streamMap . find ( streamUid ) ;
2015-03-01 00:39:48 +00:00
if ( streamInfo = = ctx - > streamMap . end ( ) ) {
2015-02-28 22:52:45 +00:00
WARN_LOG ( ME , " sceMpegGetPcmAu(%08x, %08x, %08x, %08x): bad streamUid " , mpeg , streamUid , auAddr , attrAddr ) ;
return - 1 ;
}
atracAu . write ( auAddr ) ;
u32 attr = 1 < < 7 ; // Sampling rate (1 = 44.1kHz).
attr | = 2 ; // Number of channels (1 - MONO / 2 - STEREO).
if ( Memory : : IsValidAddress ( attrAddr ) )
Memory : : Write_U32 ( attr , attrAddr ) ;
2014-01-03 19:47:59 +00:00
2015-02-28 19:15:02 +00:00
ERROR_LOG_REPORT_ONCE ( mpegPcmAu , 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-12-08 09:40:08 +00:00
static int __MpegRingbufferQueryPackNum ( u32 memorySize ) {
2014-01-28 13:56:49 +00:00
return memorySize / ( 2048 + 104 ) ;
}
2014-12-08 09:40:08 +00:00
static int sceMpegRingbufferQueryPackNum ( u32 memorySize ) {
2014-01-06 06:20:27 +00:00
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
}
2014-12-08 09:40:08 +00:00
static 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-03-02 01:19:55 +00:00
auto ringbuffer = PSPPointer < SceMpegRingBuffer > : : Create ( ctx - > mpegRingbufferAddr ) ;
if ( ringbuffer . IsValid ( ) ) {
2015-01-04 02:59:56 +00:00
ringbuffer - > packetsAvail = 0 ;
2013-03-31 17:53:40 +00:00
ringbuffer - > packetsRead = 0 ;
2016-06-05 00:34:49 +00:00
ringbuffer - > packetsWritePos = 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
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegFlushStream ( u32 mpeg , int stream_addr )
2013-01-08 08:16:18 +00:00
{
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
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static 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
2014-06-21 16:27:39 +00:00
SceMpegAu atracAu ;
atracAu . read ( auAddr ) ;
// We kept track of the stream number here in sceMpegGetAtracAu().
ctx - > mediaengine - > setAudioStream ( atracAu . esBuffer ) ;
2013-06-01 17:29:59 +00:00
Memory : : Memset ( bufferAddr , 0 , MPEG_ATRAC_ES_OUTPUT_SIZE ) ;
2013-12-11 16:21:01 +00:00
ctx - > mediaengine - > getAudioSamples ( bufferAddr ) ;
2014-06-21 16:27:39 +00:00
atracAu . pts = ctx - > mediaengine - > getAudioTimeStamp ( ) + ctx - > mpegFirstTimestamp ;
2013-06-01 17:29:59 +00:00
2014-06-21 16:27:39 +00:00
atracAu . write ( auAddr ) ;
2013-06-01 17:29:59 +00:00
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
2014-12-08 09:40:08 +00:00
static 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
2016-01-17 20:43:13 +00:00
gpu - > NotifyVideoUpload ( destAddr , destSize , frameWidth , ctx - > videoPixelMode ) ;
2015-03-03 23:21:38 +00:00
// Do not use avcDecodeDelayMs 's value
2014-05-18 04:25:32 +00:00
// Will cause video 's screen dislocation in Bleach heat of soul 6
// https://github.com/hrydgard/ppsspp/issues/5535
2015-03-03 23:21:38 +00:00
// If do not use DelayResult,Wil cause flickering in Dengeki no Pilot: Tenkuu no Kizuna
// https://github.com/hrydgard/ppsspp/issues/7549
return hleDelayResult ( 0 , " mpeg avc csc " , avcCscDelayMs ) ;
2012-11-10 09:15:11 +00:00
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static 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
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcResourceGetAvcDecTopAddr ( u32 mpeg )
2013-03-05 00:39:32 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcResourceFinish ( u32 mpeg )
2013-03-05 00:39:32 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcResourceGetAvcEsBuf ( u32 mpeg )
2013-03-05 00:39:32 +00:00
{
2015-02-28 19:15:02 +00:00
ERROR_LOG_REPORT_ONCE ( mpegResourceEsBuf , ME , " UNIMPL sceMpegAvcResourceGetAvcEsBuf(%08x) " , mpeg ) ;
2013-03-05 00:39:32 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcResourceInit ( u32 mpeg )
2013-03-05 00:39:32 +00:00
{
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
2014-12-08 09:40:08 +00:00
static 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
2014-12-08 09:40:08 +00:00
static 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 ;
}
2014-12-08 09:40:08 +00:00
static 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
2014-02-04 00:00:29 +00:00
if ( ctx - > mediaengine - > m_buffer = = 0 ) {
2014-02-08 15:20:49 +00:00
WARN_LOG ( ME , " sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): m_buffer is zero " , mpeg , bufferOutputAddr , unknown1 , unknown2 ) ;
return ERROR_MPEG_AVC_INVALID_VALUE ;
2014-02-04 00:00:29 +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 ;
}
2014-12-08 09:40:08 +00:00
static int sceMpegGetUserdataAu ( u32 mpeg , u32 streamUid , u32 auAddr , u32 resultAddr )
2013-04-08 07:46:26 +00:00
{
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-12-08 09:40:08 +00:00
static u32 sceMpegNextAvcRpAu ( u32 mpeg , u32 streamUid )
2014-01-28 13:56:49 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegGetAvcNalAu ( u32 mpeg )
2014-01-28 13:56:49 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcDecodeDetailIndex ( u32 mpeg )
2014-01-28 13:56:49 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcDecodeDetail2 ( u32 mpeg )
2014-01-28 13:56:49 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegGetAvcEsAu ( u32 mpeg )
2014-01-28 13:56:49 +00:00
{
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-12-08 09:40:08 +00:00
static u32 sceMpegAvcCscInfo ( u32 mpeg )
2014-01-28 14:03:11 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegAvcCscMode ( u32 mpeg )
2014-01-28 14:03:11 +00:00
{
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 ;
}
2014-12-08 09:40:08 +00:00
static u32 sceMpegFlushAu ( u32 mpeg )
2014-01-28 14:03:11 +00:00
{
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 [ ] =
{
2015-03-22 23:57:56 +00:00
{ 0XE1CE83A7 , & WrapI_UUUU < sceMpegGetAtracAu > , " sceMpegGetAtracAu " , ' i ' , " xxxx " } ,
{ 0XFE246728 , & WrapI_UUUU < sceMpegGetAvcAu > , " sceMpegGetAvcAu " , ' i ' , " xxxx " } ,
{ 0XD8C5F121 , & WrapU_UUUUUUU < sceMpegCreate > , " sceMpegCreate " , ' x ' , " xxxxxxx " } ,
{ 0XF8DCB679 , & WrapI_UUU < sceMpegQueryAtracEsSize > , " sceMpegQueryAtracEsSize " , ' i ' , " xxx " } ,
{ 0XC132E22F , & WrapU_V < sceMpegQueryMemSize > , " sceMpegQueryMemSize " , ' x ' , " " } ,
{ 0X21FF80E4 , & WrapI_UUU < sceMpegQueryStreamOffset > , " sceMpegQueryStreamOffset " , ' i ' , " xxx " } ,
{ 0X611E9E11 , & WrapU_UU < sceMpegQueryStreamSize > , " sceMpegQueryStreamSize " , ' x ' , " xx " } ,
{ 0X42560F23 , & WrapI_UUU < sceMpegRegistStream > , " sceMpegRegistStream " , ' i ' , " xxx " } ,
{ 0X591A4AA2 , & WrapU_UI < sceMpegUnRegistStream > , " sceMpegUnRegistStream " , ' x ' , " xi " } ,
{ 0X707B7629 , & WrapU_U < sceMpegFlushAllStream > , " sceMpegFlushAllStream " , ' x ' , " x " } ,
{ 0X500F0429 , & WrapU_UI < sceMpegFlushStream > , " sceMpegFlushStream " , ' x ' , " xi " } ,
{ 0XA780CF7E , & WrapI_U < sceMpegMallocAvcEsBuf > , " sceMpegMallocAvcEsBuf " , ' i ' , " x " } ,
{ 0XCEB870B1 , & WrapI_UI < sceMpegFreeAvcEsBuf > , " sceMpegFreeAvcEsBuf " , ' i ' , " xi " } ,
{ 0X167AFD9E , & WrapI_UUU < sceMpegInitAu > , " sceMpegInitAu " , ' i ' , " xxx " } ,
{ 0X682A619B , & WrapU_V < sceMpegInit > , " sceMpegInit " , ' x ' , " " } ,
{ 0X606A4649 , & WrapI_U < sceMpegDelete > , " sceMpegDelete " , ' i ' , " x " } ,
{ 0X874624D6 , & WrapU_V < sceMpegFinish > , " sceMpegFinish " , ' x ' , " " } ,
{ 0X800C44DF , & WrapU_UUUI < sceMpegAtracDecode > , " sceMpegAtracDecode " , ' x ' , " xxxi " } ,
{ 0X0E3C2E9D , & WrapU_UUUUU < sceMpegAvcDecode > , " sceMpegAvcDecode " , ' x ' , " xxxxx " } ,
{ 0X740FCCD1 , & WrapU_UUUU < sceMpegAvcDecodeStop > , " sceMpegAvcDecodeStop " , ' x ' , " xxxx " } ,
{ 0X4571CC64 , & WrapU_U < sceMpegAvcDecodeFlush > , " sceMpegAvcDecodeFlush " , ' x ' , " x " } ,
{ 0X0F6C18D7 , & WrapI_UU < sceMpegAvcDecodeDetail > , " sceMpegAvcDecodeDetail " , ' i ' , " xx " } ,
{ 0XA11C7026 , & WrapI_UU < sceMpegAvcDecodeMode > , " sceMpegAvcDecodeMode " , ' i ' , " xx " } ,
{ 0X37295ED8 , & WrapU_UUUUUU < sceMpegRingbufferConstruct > , " sceMpegRingbufferConstruct " , ' x ' , " xxxxxx " } ,
{ 0X13407F13 , & WrapU_U < sceMpegRingbufferDestruct > , " sceMpegRingbufferDestruct " , ' x ' , " x " } ,
2016-06-04 21:17:29 +00:00
{ 0XB240A59E , & WrapU_UII < sceMpegRingbufferPut > , " sceMpegRingbufferPut " , ' x ' , " xxx " } ,
2015-03-22 23:57:56 +00:00
{ 0XB5F6DC87 , & WrapI_U < sceMpegRingbufferAvailableSize > , " sceMpegRingbufferAvailableSize " , ' i ' , " x " } ,
{ 0XD7A29F46 , & WrapU_I < sceMpegRingbufferQueryMemSize > , " sceMpegRingbufferQueryMemSize " , ' x ' , " i " } ,
{ 0X769BEBB6 , & WrapI_U < sceMpegRingbufferQueryPackNum > , " sceMpegRingbufferQueryPackNum " , ' i ' , " x " } ,
{ 0X211A057C , & WrapI_UUUUU < sceMpegAvcQueryYCbCrSize > , " sceMpegAvcQueryYCbCrSize " , ' i ' , " xxxxx " } ,
{ 0XF0EB1125 , & WrapI_UUUU < sceMpegAvcDecodeYCbCr > , " sceMpegAvcDecodeYCbCr " , ' i ' , " xxxx " } ,
{ 0XF2930C9C , & WrapU_UUU < sceMpegAvcDecodeStopYCbCr > , " sceMpegAvcDecodeStopYCbCr " , ' x ' , " xxx " } ,
{ 0X67179B1B , & WrapU_UIIIU < sceMpegAvcInitYCbCr > , " sceMpegAvcInitYCbCr " , ' x ' , " xiiix " } ,
{ 0X0558B075 , & WrapU_UUU < sceMpegAvcCopyYCbCr > , " sceMpegAvcCopyYCbCr " , ' x ' , " xxx " } ,
{ 0X31BD0272 , & WrapU_UUUIU < sceMpegAvcCsc > , " sceMpegAvcCsc " , ' x ' , " xxxix " } ,
{ 0X9DCFB7EA , & WrapU_UII < sceMpegChangeGetAuMode > , " sceMpegChangeGetAuMode " , ' x ' , " xii " } ,
{ 0X8C1E027D , & WrapU_UIUU < sceMpegGetPcmAu > , " sceMpegGetPcmAu " , ' x ' , " xixx " } ,
{ 0XC02CF6B5 , & WrapI_UUU < sceMpegQueryPcmEsSize > , " sceMpegQueryPcmEsSize " , ' i ' , " xxx " } ,
{ 0XC45C99CC , & WrapU_UUU < sceMpegQueryUserdataEsSize > , " sceMpegQueryUserdataEsSize " , ' x ' , " xxx " } ,
{ 0X234586AE , & WrapU_UUI < sceMpegChangeGetAvcAuMode > , " sceMpegChangeGetAvcAuMode " , ' x ' , " xxi " } ,
{ 0X63B9536A , & WrapU_U < sceMpegAvcResourceGetAvcDecTopAddr > , " sceMpegAvcResourceGetAvcDecTopAddr " , ' x ' , " x " } ,
{ 0X8160A2FE , & WrapU_U < sceMpegAvcResourceFinish > , " sceMpegAvcResourceFinish " , ' x ' , " x " } ,
{ 0XAF26BB01 , & WrapU_U < sceMpegAvcResourceGetAvcEsBuf > , " sceMpegAvcResourceGetAvcEsBuf " , ' x ' , " x " } ,
{ 0XFCBDB5AD , & WrapU_U < sceMpegAvcResourceInit > , " sceMpegAvcResourceInit " , ' x ' , " x " } ,
{ 0XF5E7EA31 , & WrapI_UUUI < sceMpegAvcConvertToYuv420 > , " sceMpegAvcConvertToYuv420 " , ' i ' , " xxxi " } ,
{ 0X01977054 , & WrapI_UUUU < sceMpegGetUserdataAu > , " sceMpegGetUserdataAu " , ' i ' , " xxxx " } ,
{ 0X3C37A7A6 , & WrapU_UU < sceMpegNextAvcRpAu > , " sceMpegNextAvcRpAu " , ' x ' , " xx " } ,
{ 0X11F95CF1 , & WrapU_U < sceMpegGetAvcNalAu > , " sceMpegGetAvcNalAu " , ' x ' , " x " } ,
{ 0XAB0E9556 , & WrapU_U < sceMpegAvcDecodeDetailIndex > , " sceMpegAvcDecodeDetailIndex " , ' x ' , " x " } ,
{ 0XCF3547A2 , & WrapU_U < sceMpegAvcDecodeDetail2 > , " sceMpegAvcDecodeDetail2 " , ' x ' , " x " } ,
{ 0X921FCCCF , & WrapU_U < sceMpegGetAvcEsAu > , " sceMpegGetAvcEsAu " , ' x ' , " x " } ,
{ 0XE95838F6 , & WrapU_U < sceMpegAvcCscInfo > , " sceMpegAvcCscInfo " , ' x ' , " x " } ,
{ 0XD1CE4950 , & WrapU_U < sceMpegAvcCscMode > , " sceMpegAvcCscMode " , ' x ' , " x " } ,
{ 0XDBB60658 , & WrapU_U < sceMpegFlushAu > , " sceMpegFlushAu " , ' x ' , " x " } ,
{ 0XD4DD6E75 , nullptr , " sceMpeg_D4DD6E75 " , ' ? ' , " " } ,
{ 0X11CAB459 , nullptr , " sceMpeg_11CAB459 " , ' ? ' , " " } ,
{ 0XC345DED2 , nullptr , " sceMpeg_C345DED2 " , ' ? ' , " " } ,
{ 0XB27711A8 , nullptr , " sceMpeg_B27711A8 " , ' ? ' , " " } ,
{ 0X988E9E12 , nullptr , " sceMpeg_988E9E12 " , ' ? ' , " " } ,
2012-11-01 15:19:01 +00:00
} ;
void Register_sceMpeg ( )
{
RegisterModule ( " sceMpeg " , ARRAY_SIZE ( sceMpeg ) , sceMpeg ) ;
}
2014-03-26 16:51:07 +00:00
2014-04-04 21:01:25 +00:00
// This function is currently only been used for PMP videos
// p pointing to a SceMpegLLI structure consists of video frame blocks.
2014-12-08 09:40:08 +00:00
static u32 sceMpegbase_BEA18F91 ( u32 p )
2014-03-28 17:49:32 +00:00
{
2014-04-04 21:01:25 +00:00
pmp_videoSource = p ;
pmp_nBlocks = 0 ;
2014-03-28 17:49:32 +00:00
SceMpegLLI lli ;
2014-03-31 22:27:39 +00:00
while ( 1 ) {
Memory : : ReadStruct ( p , & lli ) ;
2014-04-04 21:01:25 +00:00
pmp_nBlocks + + ;
// lli.Next ==0 for last block
2014-03-31 22:27:39 +00:00
if ( lli . Next = = 0 ) {
break ;
}
p = p + sizeof ( SceMpegLLI ) ;
}
2014-04-04 21:01:25 +00:00
DEBUG_LOG ( ME , " sceMpegbase_BEA18F91(%08x), received %d block(s) " , pmp_videoSource , pmp_nBlocks ) ;
2014-03-26 16:51:07 +00:00
return 0 ;
}
const HLEFunction sceMpegbase [ ] =
{
2015-03-22 23:57:56 +00:00
{ 0XBEA18F91 , & WrapU_U < sceMpegbase_BEA18F91 > , " sceMpegbase_BEA18F91 " , ' x ' , " x " } ,
{ 0X492B5E4B , nullptr , " sceMpegBaseCscInit " , ' ? ' , " " } ,
{ 0X0530BE4E , nullptr , " sceMpegbase_0530BE4E " , ' ? ' , " " } ,
{ 0X91929A21 , nullptr , " sceMpegBaseCscAvc " , ' ? ' , " " } ,
{ 0X304882E1 , nullptr , " sceMpegBaseCscAvcRange " , ' ? ' , " " } ,
{ 0X7AC0321A , nullptr , " sceMpegBaseYCrCbCopy " , ' ? ' , " " }
2014-03-26 16:51:07 +00:00
} ;
void Register_sceMpegbase ( )
{
RegisterModule ( " sceMpegbase " , ARRAY_SIZE ( sceMpegbase ) , sceMpegbase ) ;
} ;