2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2014-12-11 20:25:11 +01:00
# include "Emu/System.h"
2016-03-21 20:43:03 +01:00
# include "Emu/Cell/PPUModule.h"
2014-08-23 22:40:04 +02:00
2024-02-29 21:45:28 +01:00
# include <bitset>
2014-01-19 11:52:30 +01:00
# include "cellPamf.h"
2013-09-28 04:36:57 +02:00
2025-04-05 21:50:45 +02:00
const std : : function < bool ( ) > SQUEUE_ALWAYS_EXIT = [ ] ( )
{
return true ;
} ;
const std : : function < bool ( ) > SQUEUE_NEVER_EXIT = [ ] ( )
{
return false ;
} ;
2016-03-21 20:43:03 +01:00
bool squeue_test_exit ( )
{
return Emu . IsStopped ( ) ;
}
2018-08-25 14:39:00 +02:00
LOG_CHANNEL ( cellPamf ) ;
2014-05-02 08:30:32 +02:00
2025-04-05 21:50:45 +02:00
template < >
2020-07-16 12:14:57 +02:00
void fmt_class_string < CellPamfError > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
2025-04-05 21:50:45 +02:00
switch ( error )
{
STR_CASE ( CELL_PAMF_ERROR_STREAM_NOT_FOUND ) ;
STR_CASE ( CELL_PAMF_ERROR_INVALID_PAMF ) ;
STR_CASE ( CELL_PAMF_ERROR_INVALID_ARG ) ;
STR_CASE ( CELL_PAMF_ERROR_UNKNOWN_TYPE ) ;
STR_CASE ( CELL_PAMF_ERROR_UNSUPPORTED_VERSION ) ;
STR_CASE ( CELL_PAMF_ERROR_UNKNOWN_STREAM ) ;
STR_CASE ( CELL_PAMF_ERROR_EP_NOT_FOUND ) ;
STR_CASE ( CELL_PAMF_ERROR_NOT_AVAILABLE ) ;
}
2020-07-16 12:14:57 +02:00
2025-04-05 21:50:45 +02:00
return unknown ;
} ) ;
2020-07-16 12:14:57 +02:00
}
2024-02-29 21:45:28 +01:00
error_code pamfVerifyMagicAndVersion ( vm : : cptr < PamfHeader > pAddr , vm : : ptr < CellPamfReader > pSelf )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
ensure ( ! ! pAddr ) ; // Not checked on LLE
if ( pAddr - > magic ! = std : : bit_cast < be_t < u32 > > ( " PAMF " _u32 ) )
{
return CELL_PAMF_ERROR_UNKNOWN_TYPE ;
}
if ( pSelf )
{
pSelf - > isPsmf = false ;
}
be_t < u16 > version ;
if ( pAddr - > version = = std : : bit_cast < be_t < u32 > > ( " 0040 " _u32 ) )
{
version = 40 ;
}
else if ( pAddr - > version = = std : : bit_cast < be_t < u32 > > ( " 0041 " _u32 ) )
{
version = 41 ;
}
else
{
return CELL_PAMF_ERROR_UNSUPPORTED_VERSION ;
}
if ( pSelf )
{
pSelf - > version = version ;
}
return CELL_OK ;
}
error_code pamfGetHeaderAndDataSize ( vm : : cptr < PamfHeader > pAddr , u64 fileSize , vm : : ptr < u64 > headerSize , vm : : ptr < u64 > dataSize )
{
ensure ( ! ! pAddr ) ; // Not checked on LLE
if ( error_code ret = pamfVerifyMagicAndVersion ( pAddr , vm : : null ) ; ret ! = CELL_OK )
{
return ret ;
}
const u64 header_size = pAddr - > header_size * 0x800ull ;
const u64 data_size = pAddr - > data_size * 0x800ull ;
if ( header_size = = 0 | | ( fileSize ! = 0 & & header_size + data_size ! = fileSize ) )
{
return CELL_PAMF_ERROR_INVALID_PAMF ;
}
if ( headerSize )
{
* headerSize = header_size ;
}
if ( dataSize )
{
* dataSize = data_size ;
}
return CELL_OK ;
}
error_code pamfTypeChannelToStream ( u8 type , u8 ch , u8 * stream_coding_type , u8 * stream_id , u8 * private_stream_id )
{
// This function breaks if ch is greater than 15, LLE doesn't check for this
2020-12-09 08:47:45 +01:00
ensure ( ch < 16 ) ;
2024-02-29 21:45:28 +01:00
u8 _stream_coding_type ;
u8 _stream_id ;
u8 _private_stream_id ;
2018-08-25 14:39:00 +02:00
2014-01-18 00:45:07 +01:00
switch ( type )
{
case CELL_PAMF_STREAM_TYPE_AVC :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_AVC ;
_stream_id = 0xe0 | ch ;
_private_stream_id = 0 ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-11 20:25:11 +01:00
}
case CELL_PAMF_STREAM_TYPE_M2V :
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_M2V ;
_stream_id = 0xe0 | ch ;
_private_stream_id = 0 ;
2014-12-11 20:25:11 +01:00
break ;
}
2018-08-25 14:39:00 +02:00
2014-01-18 00:45:07 +01:00
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_ATRAC3PLUS ;
_stream_id = 0xbd ;
_private_stream_id = ch ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-11 20:25:11 +01:00
}
2018-08-25 14:39:00 +02:00
2014-01-18 00:45:07 +01:00
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_PAMF_LPCM ;
_stream_id = 0xbd ;
_private_stream_id = 0x40 | ch ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-11 20:25:11 +01:00
}
case CELL_PAMF_STREAM_TYPE_AC3 :
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_AC3 ;
_stream_id = 0xbd ;
_private_stream_id = 0x30 | ch ;
2014-12-11 20:25:11 +01:00
break ;
}
2018-08-25 14:39:00 +02:00
2014-01-18 00:45:07 +01:00
case CELL_PAMF_STREAM_TYPE_USER_DATA :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_USER_DATA ;
_stream_id = 0xbd ;
_private_stream_id = 0x20 | ch ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_AVC :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_PSMF ;
_stream_id = 0xe0 | ch ;
_private_stream_id = 0 ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_ATRAC3PLUS :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_PSMF ;
_stream_id = 0xbd ;
_private_stream_id = ch ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_LPCM :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_PSMF ;
_stream_id = 0xbd ;
_private_stream_id = 0x10 | ch ;
2014-12-11 20:25:11 +01:00
break ;
}
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_USER_DATA :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
_stream_coding_type = PAMF_STREAM_CODING_TYPE_PSMF ;
_stream_id = 0xbd ;
_private_stream_id = 0x20 | ch ;
2014-12-11 20:25:11 +01:00
break ;
}
2018-08-25 14:39:00 +02:00
2014-01-18 00:45:07 +01:00
default :
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
cellPamf . error ( " pamfTypeChannelToStream(): unknown type %d " , type ) ;
2014-01-18 00:45:07 +01:00
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
if ( stream_coding_type )
{
* stream_coding_type = _stream_coding_type ;
}
if ( stream_id )
{
* stream_id = _stream_id ;
}
if ( private_stream_id )
{
* private_stream_id = _private_stream_id ;
}
2014-01-18 00:45:07 +01:00
return CELL_OK ;
}
2024-02-29 21:45:28 +01:00
error_code pamfStreamToTypeChannel ( u8 stream_coding_type , u8 stream_id , u8 private_stream_id , vm : : ptr < u8 > type , vm : : ptr < u8 > ch )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
u8 _type ;
u8 _ch ;
2014-12-11 20:25:11 +01:00
2024-02-29 21:45:28 +01:00
switch ( stream_coding_type )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
case PAMF_STREAM_CODING_TYPE_AVC :
_type = CELL_PAMF_STREAM_TYPE_AVC ;
_ch = stream_id & 0x0f ;
break ;
case PAMF_STREAM_CODING_TYPE_M2V :
_type = CELL_PAMF_STREAM_TYPE_M2V ;
_ch = stream_id & 0x0f ;
break ;
case PAMF_STREAM_CODING_TYPE_ATRAC3PLUS :
_type = CELL_PAMF_STREAM_TYPE_ATRAC3PLUS ;
_ch = private_stream_id & 0x0f ;
break ;
case PAMF_STREAM_CODING_TYPE_PAMF_LPCM :
_type = CELL_PAMF_STREAM_TYPE_PAMF_LPCM ;
_ch = private_stream_id & 0x0f ;
break ;
case PAMF_STREAM_CODING_TYPE_AC3 :
_type = CELL_PAMF_STREAM_TYPE_AC3 ;
_ch = private_stream_id & 0x0f ;
break ;
case PAMF_STREAM_CODING_TYPE_USER_DATA :
_type = CELL_PAMF_STREAM_TYPE_USER_DATA ;
_ch = private_stream_id & 0x0f ;
break ;
case PAMF_STREAM_CODING_TYPE_PSMF :
if ( ( stream_id & 0xf0 ) = = 0xe0 )
{
_type = CELL_PAMF_STREAM_TYPE_PSMF_AVC ;
_ch = stream_id & 0x0f ;
if ( private_stream_id ! = 0 )
{
return CELL_PAMF_ERROR_STREAM_NOT_FOUND ;
}
}
else if ( stream_id = = 0xbd )
{
_ch = private_stream_id & 0x0f ;
switch ( private_stream_id & 0xf0 )
{
case 0x00 : _type = CELL_PAMF_STREAM_TYPE_PSMF_ATRAC3PLUS ; break ;
case 0x10 : _type = CELL_PAMF_STREAM_TYPE_PSMF_LPCM ; break ;
case 0x20 : _type = CELL_PAMF_STREAM_TYPE_PSMF_LPCM ; break ; // LLE doesn't use CELL_PAMF_STREAM_TYPE_PSMF_USER_DATA for some reason
default : return CELL_PAMF_ERROR_STREAM_NOT_FOUND ;
}
}
else
{
return CELL_PAMF_ERROR_STREAM_NOT_FOUND ;
}
break ;
default :
cellPamf . error ( " pamfStreamToTypeChannel(): unknown stream_coding_type 0x%02x " , stream_coding_type ) ;
return CELL_PAMF_ERROR_STREAM_NOT_FOUND ;
}
if ( type )
{
* type = _type ;
}
if ( ch )
{
* ch = _ch ;
2014-01-18 00:45:07 +01:00
}
2014-12-11 20:25:11 +01:00
2024-02-29 21:45:28 +01:00
return CELL_OK ;
}
void pamfEpUnpack ( vm : : cptr < PamfEpHeader > ep_packed , vm : : ptr < CellPamfEp > ep )
{
ensure ( ! ! ep_packed & & ! ! ep ) ; // Not checked on LLE
ep - > indexN = ( ep_packed - > value0 > > 14 ) + 1 ;
ep - > nThRefPictureOffset = ( ( ep_packed - > value0 & 0x1fff ) * 0x800 ) + 0x800 ;
ep - > pts . upper = ep_packed - > pts_high ;
ep - > pts . lower = ep_packed - > pts_low ;
ep - > rpnOffset = ep_packed - > rpnOffset * 0x800ull ;
2014-01-18 00:45:07 +01:00
}
2024-02-29 21:45:28 +01:00
void psmfEpUnpack ( vm : : cptr < PsmfEpHeader > ep_packed , vm : : ptr < CellPamfEp > ep )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
ensure ( ! ! ep_packed & & ! ! ep ) ; // Not checked on LLE
2014-01-18 00:45:07 +01:00
2024-02-29 21:45:28 +01:00
ep - > indexN = ( ep_packed - > value0 > > 14 ) + 1 ;
ep - > nThRefPictureOffset = ( ( ep_packed - > value0 & 0xffe ) * 0x400 ) + 0x800 ;
ep - > pts . upper = ep_packed - > value0 & 1 ;
ep - > pts . lower = ep_packed - > pts_low ;
ep - > rpnOffset = ep_packed - > rpnOffset * 0x800ull ;
}
bool pamfIsSameStreamType ( u8 type , u8 requested_type )
{
switch ( requested_type )
2014-02-26 08:51:00 +01:00
{
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_VIDEO : return type = = CELL_PAMF_STREAM_TYPE_AVC | | type = = CELL_PAMF_STREAM_TYPE_M2V ;
case CELL_PAMF_STREAM_TYPE_AUDIO : return type = = CELL_PAMF_STREAM_TYPE_ATRAC3PLUS | | type = = CELL_PAMF_STREAM_TYPE_AC3 | | type = = CELL_PAMF_STREAM_TYPE_PAMF_LPCM ;
2025-04-05 21:50:45 +02:00
case CELL_PAMF_STREAM_TYPE_UNK : return type = = CELL_PAMF_STREAM_TYPE_PAMF_LPCM | | type = = CELL_PAMF_STREAM_TYPE_PSMF_ATRAC3PLUS ; // ??? no idea what this is for
default : return requested_type = = type ;
2024-02-29 21:45:28 +01:00
}
}
error_code pamfVerify ( vm : : cptr < PamfHeader > pAddr , u64 fileSize , vm : : ptr < CellPamfReader > pSelf , u32 attribute )
{
ensure ( ! ! pAddr ) ; // Not checked on LLE
if ( error_code ret = pamfVerifyMagicAndVersion ( pAddr , pSelf ) ; ret ! = CELL_OK )
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
return ret ;
2014-12-11 20:25:11 +01:00
}
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
const u64 header_size = pAddr - > header_size * 0x800ull ;
const u64 data_size = pAddr - > data_size * 0x800ull ;
// Header size
if ( header_size = = 0 )
2014-12-11 20:25:11 +01:00
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid header_size " } ;
2014-12-11 20:25:11 +01:00
}
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
if ( pSelf )
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
pSelf - > headerSize = header_size ;
pSelf - > dataSize = data_size ;
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
// Data size
if ( fileSize ! = 0 & & header_size + data_size ! = fileSize )
2014-12-11 20:25:11 +01:00
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: fileSize isn't equal header_size + data_size " } ;
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
const u32 psmf_marks_offset = pAddr - > psmf_marks_offset ;
const u32 psmf_marks_size = pAddr - > psmf_marks_size ;
const u32 unk_offset = pAddr - > unk_offset ;
const u32 unk_size = pAddr - > unk_size ;
// PsmfMarks
if ( psmf_marks_offset = = 0 )
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
if ( psmf_marks_size ! = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: psmf_marks_offset is zero but psmf_marks_size is not zero " } ;
2024-02-29 21:45:28 +01:00
}
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
else
{
if ( psmf_marks_size = = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: psmf_marks_offset is set but psmf_marks_size is zero " } ;
2024-02-29 21:45:28 +01:00
}
if ( header_size < static_cast < u64 > ( psmf_marks_offset ) + psmf_marks_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: header_size is less than psmf_marks_offset + psmf_marks_size " } ;
2024-02-29 21:45:28 +01:00
}
2014-02-26 08:51:00 +01:00
}
2014-07-06 20:26:05 +02:00
2024-02-29 21:45:28 +01:00
if ( unk_offset = = 0 )
{
if ( unk_size ! = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: unk_offset is zero but unk_size is not zero " } ;
2024-02-29 21:45:28 +01:00
}
}
else
{
if ( unk_size = = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: unk_offset is set but unk_size is zero " } ;
2024-02-29 21:45:28 +01:00
}
if ( header_size < static_cast < u64 > ( unk_offset ) + unk_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: header_size is less than unk_offset + unk_size " } ;
2024-02-29 21:45:28 +01:00
}
}
if ( unk_offset < static_cast < u64 > ( psmf_marks_offset ) + psmf_marks_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: unk_offset is less than psmf_marks_offset + psmf_marks_size " } ;
2024-02-29 21:45:28 +01:00
}
// Sequence Info
const u32 seq_info_size = pAddr - > seq_info . size ;
// Sequence info size
if ( offsetof ( PamfHeader , seq_info ) + sizeof ( u32 ) + seq_info_size > header_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid seq_info_size " } ;
2024-02-29 21:45:28 +01:00
}
const u64 start_pts = static_cast < u64 > ( pAddr - > seq_info . start_pts_high ) < < 32 | pAddr - > seq_info . start_pts_low ;
const u64 end_pts = static_cast < u64 > ( pAddr - > seq_info . end_pts_high ) < < 32 | pAddr - > seq_info . end_pts_low ;
// Start and end presentation time stamps
if ( end_pts > CODEC_TS_INVALID )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid end_pts " } ;
2024-02-29 21:45:28 +01:00
}
if ( start_pts > = end_pts )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid start_pts " } ;
2024-02-29 21:45:28 +01:00
}
// Grouping period count
if ( pAddr - > seq_info . grouping_period_num ! = 1 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid grouping_period_num " } ;
2024-02-29 21:45:28 +01:00
}
// Grouping Period
const u32 grouping_period_size = pAddr - > seq_info . grouping_periods . size ;
// Grouping period size
if ( offsetof ( PamfHeader , seq_info . grouping_periods ) + sizeof ( u32 ) + grouping_period_size > header_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid grouping_period_size " } ;
2024-02-29 21:45:28 +01:00
}
const u64 grp_period_start_pts = static_cast < u64 > ( pAddr - > seq_info . grouping_periods . start_pts_high ) < < 32 | pAddr - > seq_info . grouping_periods . start_pts_low ;
const u64 grp_period_end_pts = static_cast < u64 > ( pAddr - > seq_info . grouping_periods . start_pts_high ) < < 32 | pAddr - > seq_info . grouping_periods . end_pts_low ; // LLE uses start_pts_high due to a bug
// Start and end presentation time stamps
if ( grp_period_end_pts > CODEC_TS_INVALID )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid grp_period_end_pts " } ;
2024-02-29 21:45:28 +01:00
}
if ( grp_period_start_pts > = grp_period_end_pts )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid grp_period_start_pts " } ;
2024-02-29 21:45:28 +01:00
}
if ( grp_period_start_pts ! = start_pts )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: grp_period_start_pts not equal start_pts " } ;
2024-02-29 21:45:28 +01:00
}
// Group count
if ( pAddr - > seq_info . grouping_periods . group_num ! = 1 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid group_num " } ;
2024-02-29 21:45:28 +01:00
}
// Group
const u32 group_size = pAddr - > seq_info . grouping_periods . groups . size ;
// StreamGroup size
if ( offsetof ( PamfHeader , seq_info . grouping_periods . groups ) + sizeof ( u32 ) + group_size > header_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid group_size " } ;
2024-02-29 21:45:28 +01:00
}
const u8 stream_num = pAddr - > seq_info . grouping_periods . groups . stream_num ;
// Stream count
if ( stream_num = = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid stream_num " } ;
2024-02-29 21:45:28 +01:00
}
// Streams
const auto streams = & pAddr - > seq_info . grouping_periods . groups . streams ;
std : : bitset < 16 > channels_used [ 6 ] { } ;
u32 end_of_streams_addr = 0 ;
u32 next_ep_table_addr = 0 ;
for ( u8 stream_idx = 0 ; stream_idx < stream_num ; stream_idx + + )
{
vm : : var < u8 > type ;
vm : : var < u8 > ch ;
// Stream coding type and IDs
if ( pamfStreamToTypeChannel ( streams [ stream_idx ] . stream_coding_type , streams [ stream_idx ] . stream_id , streams [ stream_idx ] . private_stream_id , type , ch ) ! = CELL_OK )
{
return CELL_PAMF_ERROR_UNKNOWN_STREAM ;
}
// Every channel may only be used once per type
if ( channels_used [ * type ] . test ( * ch ) )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid channel " } ;
2024-02-29 21:45:28 +01:00
}
// Mark channel as used
channels_used [ * type ] . set ( * ch ) ;
const u32 ep_offset = streams [ stream_idx ] . ep_offset ;
const u32 ep_num = streams [ stream_idx ] . ep_num ;
// Entry point offset and number
if ( ep_num = = 0 )
{
if ( ep_offset ! = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: ep_num is zero but ep_offset is not zero " } ;
2024-02-29 21:45:28 +01:00
}
}
else
{
if ( ep_offset = = 0 )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid ep_offset " } ;
2024-02-29 21:45:28 +01:00
}
if ( ep_offset + ep_num * sizeof ( PamfEpHeader ) > header_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid ep_num " } ;
2024-02-29 21:45:28 +01:00
}
}
// Entry points
// Skip if there are no entry points or if the minimum header attribute is set
if ( ep_offset = = 0 | | attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER )
{
continue ;
}
const auto eps = vm : : cptr < PamfEpHeader > : : make ( pAddr . addr ( ) + ep_offset ) ;
// Entry point tables must be sorted by the stream index to which they belong
// and there mustn't be any gaps between them
if ( end_of_streams_addr = = 0 )
{
end_of_streams_addr = eps . addr ( ) ;
next_ep_table_addr = end_of_streams_addr ;
}
else if ( next_ep_table_addr ! = eps . addr ( ) )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid ep table address " } ;
2024-02-29 21:45:28 +01:00
}
u64 previous_rpn_offset = 0 ;
for ( u32 ep_idx = 0 ; ep_idx < ep_num ; ep_idx + + )
{
const u64 pts = static_cast < u64 > ( eps [ ep_idx ] . pts_high ) < < 32 | eps [ ep_idx ] . pts_low ;
// Entry point time stamp
if ( pts > CODEC_TS_INVALID )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid ep pts " } ;
2024-02-29 21:45:28 +01:00
}
const u64 rpn_offset = eps [ ep_idx ] . rpnOffset * 0x800ull ;
// Entry point rpnOffset
if ( rpn_offset > data_size | | rpn_offset < previous_rpn_offset )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid rpn_offset " } ;
2024-02-29 21:45:28 +01:00
}
previous_rpn_offset = rpn_offset ;
}
next_ep_table_addr + = ep_num * sizeof ( PamfEpHeader ) ;
}
// This can overflow on LLE, the +4 is necessary on both sides and the left operand needs to be u32
2025-04-05 21:50:45 +02:00
if ( group_size + 4 > grouping_period_size - offsetof ( PamfGroupingPeriod , groups ) + sizeof ( u32 ) | | grouping_period_size + 4 > seq_info_size - offsetof ( PamfSequenceInfo , grouping_periods ) + sizeof ( u32 ) )
2024-02-29 21:45:28 +01:00
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: size mismatch " } ;
2024-02-29 21:45:28 +01:00
}
// Since multiple grouping periods/groups was never implemented, number of streams in SequenceInfo must be equal stream_num in Group
if ( pAddr - > seq_info . total_stream_num ! = stream_num )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: number of streams mismatch " } ;
2024-02-29 21:45:28 +01:00
}
// PsmfMarks
// This is probably useless since the official PAMF tools don't support PsmfMarks
if ( end_of_streams_addr = = 0 )
{
if ( psmf_marks_offset ! = 0 )
{
end_of_streams_addr = pAddr . addr ( ) + psmf_marks_offset ;
}
else if ( unk_offset ! = 0 )
{
end_of_streams_addr = pAddr . addr ( ) + unk_offset ;
}
}
if ( end_of_streams_addr ! = 0 & & pAddr . addr ( ) + offsetof ( PamfHeader , seq_info . grouping_periods ) + sizeof ( u32 ) + grouping_period_size ! = end_of_streams_addr )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid offset of ep tables or psmf marks " } ;
2024-02-29 21:45:28 +01:00
}
if ( next_ep_table_addr ! = 0 & & psmf_marks_offset = = 0 )
{
if ( unk_offset ! = 0 & & pAddr . addr ( ) + unk_offset ! = next_ep_table_addr )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid unk_offset " } ;
2024-02-29 21:45:28 +01:00
}
}
else if ( next_ep_table_addr ! = 0 & & pAddr . addr ( ) + psmf_marks_offset ! = next_ep_table_addr )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid psmf_marks_offset " } ;
2024-02-29 21:45:28 +01:00
}
else if ( psmf_marks_offset ! = 0 & & ! ( attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER ) )
{
const u32 size = vm : : read32 ( pAddr . addr ( ) + psmf_marks_offset ) ;
if ( size + sizeof ( u32 ) ! = psmf_marks_size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid psmf_marks_size " } ;
2024-02-29 21:45:28 +01:00
}
const u16 marks_num = vm : : read16 ( pAddr . addr ( ) + psmf_marks_offset + 6 ) ; // LLE uses the wrong offset (6 instead of 4)
if ( sizeof ( u16 ) + marks_num * 0x28 /*sizeof PsmfMark*/ ! = size )
{
2025-04-05 21:50:45 +02:00
return { CELL_PAMF_ERROR_INVALID_PAMF , " pamfVerify() failed: invalid marks_num " } ;
2024-02-29 21:45:28 +01:00
}
// There are more checks in LLE but due to the bug above these would never be executed
}
return CELL_OK ;
2014-01-18 00:45:07 +01:00
}
2024-02-29 21:45:28 +01:00
error_code cellPamfGetStreamOffsetAndSize ( vm : : ptr < PamfHeader > pAddr , u64 fileSize , vm : : ptr < u64 > pOffset , vm : : ptr < u64 > pSize ) ;
2020-07-16 12:14:57 +02:00
error_code cellPamfGetHeaderSize ( vm : : ptr < PamfHeader > pAddr , u64 fileSize , vm : : ptr < u64 > pSize )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfGetHeaderSize(pAddr=*0x%x, fileSize=0x%llx, pSize=*0x%x) " , pAddr , fileSize , pSize ) ;
2014-01-19 11:52:30 +01:00
2024-02-29 21:45:28 +01:00
return cellPamfGetStreamOffsetAndSize ( pAddr , fileSize , pSize , vm : : null ) ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfGetHeaderSize2 ( vm : : ptr < PamfHeader > pAddr , u64 fileSize , u32 attribute , vm : : ptr < u64 > pSize )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfGetHeaderSize2(pAddr=*0x%x, fileSize=0x%llx, attribute=0x%x, pSize=*0x%x) " , pAddr , fileSize , attribute , pSize ) ;
2014-01-05 00:45:44 +01:00
2024-02-29 21:45:28 +01:00
const vm : : var < u64 > header_size ;
if ( error_code ret = cellPamfGetStreamOffsetAndSize ( pAddr , fileSize , header_size , vm : : null ) ; ret ! = CELL_OK )
{
return ret ;
}
if ( attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER )
{
if ( pAddr - > magic ! = std : : bit_cast < be_t < u32 > > ( " PAMF " _u32 ) ) // Already checked in cellPamfGetStreamOffsetAndSize(), should always evaluate to false at this point
{
return CELL_PAMF_ERROR_UNKNOWN_TYPE ;
}
const u64 min_header_size = offsetof ( PamfHeader , seq_info ) + sizeof ( u32 ) + pAddr - > seq_info . size ; // Size without EP tables
if ( min_header_size > * header_size )
{
return CELL_PAMF_ERROR_INVALID_PAMF ;
}
* header_size = min_header_size ;
}
if ( pSize )
{
* pSize = * header_size ;
}
2014-01-19 11:52:30 +01:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellPamfGetStreamOffsetAndSize ( vm : : ptr < PamfHeader > pAddr , u64 fileSize , vm : : ptr < u64 > pOffset , vm : : ptr < u64 > pSize )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfGetStreamOffsetAndSize(pAddr=*0x%x, fileSize=0x%llx, pOffset=*0x%x, pSize=*0x%x) " , pAddr , fileSize , pOffset , pSize ) ;
2014-01-19 11:52:30 +01:00
2024-02-29 21:45:28 +01:00
return pamfGetHeaderAndDataSize ( pAddr , fileSize , pOffset , pSize ) ;
2013-09-28 04:36:57 +02:00
}
2021-10-26 23:26:57 +02:00
error_code cellPamfVerify ( vm : : cptr < PamfHeader > pAddr , u64 fileSize )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfVerify(pAddr=*0x%x, fileSize=0x%llx) " , pAddr , fileSize ) ;
2014-05-18 12:46:01 +02:00
2024-02-29 21:45:28 +01:00
return pamfVerify ( pAddr , fileSize , vm : : null , CELL_PAMF_ATTRIBUTE_VERIFY_ON ) ;
2013-09-28 04:36:57 +02:00
}
2024-02-29 21:45:28 +01:00
error_code cellPamfReaderSetStreamWithIndex ( vm : : ptr < CellPamfReader > pSelf , u8 streamIndex ) ;
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderInitialize ( vm : : ptr < CellPamfReader > pSelf , vm : : cptr < PamfHeader > pAddr , u64 fileSize , u32 attribute )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderInitialize(pSelf=*0x%x, pAddr=*0x%x, fileSize=0x%llx, attribute=0x%x) " , pSelf , pAddr , fileSize , attribute ) ;
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf ) ; // Not checked on LLE
std : : memset ( pSelf . get_ptr ( ) , 0 , sizeof ( CellPamfReader ) ) ;
pSelf - > attribute = attribute ;
if ( attribute & CELL_PAMF_ATTRIBUTE_VERIFY_ON )
2014-01-06 02:50:56 +01:00
{
2024-02-29 21:45:28 +01:00
if ( error_code ret = pamfVerify ( pAddr , fileSize , pSelf , attribute ) ; ret ! = CELL_OK )
{
return ret ;
}
2014-01-06 02:50:56 +01:00
}
2024-02-29 21:45:28 +01:00
pSelf - > pamf . header = pAddr ;
pSelf - > pamf . sequenceInfo = pAddr . ptr ( & PamfHeader : : seq_info ) ;
pSelf - > currentGroupingPeriodIndex = - 1 ;
pSelf - > currentGroupIndex = - 1 ;
pSelf - > currentStreamIndex = - 1 ;
if ( pAddr - > seq_info . grouping_period_num = = 0 )
2014-01-06 02:50:56 +01:00
{
2024-02-29 21:45:28 +01:00
return CELL_PAMF_ERROR_INVALID_PAMF ;
2014-01-06 02:50:56 +01:00
}
2014-02-26 15:06:13 +01:00
2024-02-29 21:45:28 +01:00
pSelf - > currentGroupingPeriodIndex = 0 ;
pSelf - > pamf . currentGroupingPeriod = pSelf - > pamf . sequenceInfo . ptr ( & PamfSequenceInfo : : grouping_periods ) ;
if ( pAddr - > seq_info . grouping_periods . group_num ! = 0 )
2014-01-06 02:50:56 +01:00
{
2024-02-29 21:45:28 +01:00
pSelf - > currentGroupIndex = 0 ;
pSelf - > pamf . currentGroup = pSelf - > pamf . currentGroupingPeriod . ptr ( & PamfGroupingPeriod : : groups ) ;
cellPamfReaderSetStreamWithIndex ( pSelf , 0 ) ;
2014-01-06 02:50:56 +01:00
}
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetPresentationStartTime ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < CellCodecTimeStamp > pTimeStamp )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetPresentationStartTime(pSelf=*0x%x, pTimeStamp=*0x%x) " , pSelf , pTimeStamp ) ;
2014-01-06 02:50:56 +01:00
2014-12-11 20:25:11 +01:00
// always returns CELL_OK
2014-11-15 15:47:30 +01:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf & & ! ! pTimeStamp ) ; // Not checked on LLE
if ( pSelf - > isPsmf )
{
pTimeStamp - > upper = pSelf - > psmf . sequenceInfo - > start_pts_high ;
pTimeStamp - > lower = pSelf - > psmf . sequenceInfo - > start_pts_low ;
}
else
{
pTimeStamp - > upper = pSelf - > pamf . sequenceInfo - > start_pts_high ;
pTimeStamp - > lower = pSelf - > pamf . sequenceInfo - > start_pts_low ;
}
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetPresentationEndTime ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < CellCodecTimeStamp > pTimeStamp )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetPresentationEndTime(pSelf=*0x%x, pTimeStamp=*0x%x) " , pSelf , pTimeStamp ) ;
2014-01-06 02:50:56 +01:00
2014-12-11 20:25:11 +01:00
// always returns CELL_OK
2014-11-15 15:47:30 +01:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf & & ! ! pTimeStamp ) ; // Not checked on LLE
if ( pSelf - > isPsmf )
{
pTimeStamp - > upper = pSelf - > psmf . sequenceInfo - > end_pts_high ;
pTimeStamp - > lower = pSelf - > psmf . sequenceInfo - > end_pts_low ;
}
else
{
pTimeStamp - > upper = pSelf - > pamf . sequenceInfo - > end_pts_high ;
pTimeStamp - > lower = pSelf - > pamf . sequenceInfo - > end_pts_low ;
}
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2014-12-11 20:25:11 +01:00
u32 cellPamfReaderGetMuxRateBound ( vm : : ptr < CellPamfReader > pSelf )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetMuxRateBound(pSelf=*0x%x) " , pSelf ) ;
ensure ( ! ! pSelf ) ; // Not checked on LLE
if ( pSelf - > isPsmf )
{
return pSelf - > psmf . sequenceInfo - > mux_rate_bound & 0x003fffff ;
}
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
return pSelf - > pamf . sequenceInfo - > mux_rate_bound & 0x003fffff ;
2013-09-28 04:36:57 +02:00
}
2014-12-11 20:25:11 +01:00
u8 cellPamfReaderGetNumberOfStreams ( vm : : ptr < CellPamfReader > pSelf )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetNumberOfStreams(pSelf=*0x%x) " , pSelf ) ;
ensure ( ! ! pSelf ) ; // Not checked on LLE
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
return pSelf - > pamf . currentGroup - > stream_num ;
2013-09-28 04:36:57 +02:00
}
2014-12-11 20:25:11 +01:00
u8 cellPamfReaderGetNumberOfSpecificStreams ( vm : : ptr < CellPamfReader > pSelf , u8 streamType )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetNumberOfSpecificStreams(pSelf=*0x%x, streamType=%d) " , pSelf , streamType ) ;
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf ) ; // Not checked on LLE
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
const vm : : var < u8 > type ;
u8 found = 0 ;
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
if ( pSelf - > isPsmf )
2014-01-06 02:50:56 +01:00
{
2024-02-29 21:45:28 +01:00
const auto streams = pSelf - > psmf . currentGroup . ptr ( & PsmfGroup : : streams ) ;
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
for ( u8 i = 0 ; i < pSelf - > psmf . currentGroup - > stream_num ; i + + )
{
if ( pamfStreamToTypeChannel ( PAMF_STREAM_CODING_TYPE_PSMF , streams [ i ] . stream_id , streams [ i ] . private_stream_id , type , vm : : null ) = = CELL_OK )
{
found + = pamfIsSameStreamType ( * type , streamType ) ;
}
}
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
else
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
const auto streams = pSelf - > pamf . currentGroup . ptr ( & PamfGroup : : streams ) ;
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
for ( u8 i = 0 ; i < pSelf - > pamf . currentGroup - > stream_num ; i + + )
{
if ( pamfStreamToTypeChannel ( streams [ i ] . stream_coding_type , streams [ i ] . stream_id , streams [ i ] . private_stream_id , type , vm : : null ) = = CELL_OK )
{
found + = pamfIsSameStreamType ( * type , streamType ) ;
}
}
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
return found ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderSetStreamWithIndex ( vm : : ptr < CellPamfReader > pSelf , u8 streamIndex )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderSetStreamWithIndex(pSelf=*0x%x, streamIndex=%d) " , pSelf , streamIndex ) ;
ensure ( ! ! pSelf ) ; // Not checked on LLE
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
if ( streamIndex > = pSelf - > pamf . currentGroup - > stream_num )
2014-01-06 02:50:56 +01:00
{
2014-12-11 20:25:11 +01:00
return CELL_PAMF_ERROR_INVALID_ARG ;
2014-01-06 02:50:56 +01:00
}
2014-11-19 15:16:30 +01:00
2024-02-29 21:45:28 +01:00
pSelf - > currentStreamIndex = streamIndex ;
if ( pSelf - > isPsmf )
{
pSelf - > psmf . currentStream = pSelf - > psmf . currentGroup . ptr ( & PsmfGroup : : streams ) + streamIndex ;
}
else
{
pSelf - > pamf . currentStream = pSelf - > pamf . currentGroup . ptr ( & PamfGroup : : streams ) + streamIndex ;
}
2014-12-11 20:25:11 +01:00
return CELL_OK ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderSetStreamWithTypeAndChannel ( vm : : ptr < CellPamfReader > pSelf , u8 streamType , u8 ch )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderSetStreamWithTypeAndChannel(pSelf=*0x%x, streamType=%d, ch=%d) " , pSelf , streamType , ch ) ;
// This function is broken on LLE
ensure ( ! ! pSelf ) ; // Not checked on LLE
2014-11-15 15:47:30 +01:00
2024-02-29 21:45:28 +01:00
u8 stream_coding_type ;
u8 stream_id ;
u8 private_stream_id ;
if ( pamfTypeChannelToStream ( streamType , ch , & stream_coding_type , & stream_id , & private_stream_id ) ! = CELL_OK )
2014-01-18 00:45:07 +01:00
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2024-02-29 21:45:28 +01:00
const u8 stream_num = pSelf - > pamf . currentGroup - > stream_num ;
u32 i = 0 ;
if ( pSelf - > isPsmf )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
const auto streams = pSelf - > psmf . currentGroup . ptr ( & PsmfGroup : : streams ) ;
for ( ; i < stream_num ; i + + )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
// LLE increments the index by 12 instead of 1
if ( stream_coding_type = = PAMF_STREAM_CODING_TYPE_PSMF & & streams [ i * 12 ] . stream_id = = stream_id & & streams [ i * 12 ] . private_stream_id = = private_stream_id )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
break ;
2014-01-18 00:45:07 +01:00
}
}
}
2024-02-29 21:45:28 +01:00
else
{
const auto streams = pSelf - > pamf . currentGroup . ptr ( & PamfGroup : : streams ) ;
2014-01-18 00:45:07 +01:00
2024-02-29 21:45:28 +01:00
for ( ; i < stream_num ; i + + )
{
// LLE increments the index by 0x10 instead of 1
if ( streams [ i * 0x10 ] . stream_coding_type = = stream_coding_type & & streams [ i * 0x10 ] . stream_id = = stream_id & & streams [ i * 0x10 ] . private_stream_id = = private_stream_id )
{
break ;
}
}
}
if ( i = = stream_num )
{
i = CELL_PAMF_ERROR_STREAM_NOT_FOUND ; // LLE writes the error code to the index
}
if ( pSelf - > currentStreamIndex ! = i )
{
pSelf - > pamf . currentStream = pSelf - > pamf . currentGroup . ptr ( & PamfGroup : : streams ) ; // LLE always sets this to the first stream
pSelf - > currentStreamIndex = i ;
}
if ( i = = CELL_PAMF_ERROR_STREAM_NOT_FOUND )
{
return CELL_PAMF_ERROR_STREAM_NOT_FOUND ;
}
return not_an_error ( i ) ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderSetStreamWithTypeAndIndex ( vm : : ptr < CellPamfReader > pSelf , u8 streamType , u8 streamIndex )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderSetStreamWithTypeAndIndex(pSelf=*0x%x, streamType=%d, streamIndex=%d) " , pSelf , streamType , streamIndex ) ;
ensure ( ! ! pSelf ) ; // Not checked on LLE
const u8 stream_num = pSelf - > pamf . currentGroup - > stream_num ;
if ( streamIndex > = stream_num )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
const vm : : var < u8 > type ;
2014-01-06 02:50:56 +01:00
u32 found = 0 ;
2024-02-29 21:45:28 +01:00
if ( pSelf - > isPsmf )
2014-01-06 02:50:56 +01:00
{
2024-02-29 21:45:28 +01:00
const auto streams = pSelf - > psmf . currentGroup . ptr ( & PsmfGroup : : streams ) ;
2014-01-18 00:45:07 +01:00
2024-02-29 21:45:28 +01:00
for ( u8 i = 0 ; i < stream_num ; i + + )
2014-01-06 02:50:56 +01:00
{
2024-02-29 21:45:28 +01:00
if ( pamfStreamToTypeChannel ( PAMF_STREAM_CODING_TYPE_PSMF , streams [ i ] . stream_id , streams [ i ] . private_stream_id , type , vm : : null ) ! = CELL_OK )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
continue ;
2014-01-18 00:45:07 +01:00
}
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
found + = * type = = streamType ;
if ( found > streamIndex )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
pSelf - > currentStreamIndex = streamIndex ; // LLE sets this to the index counting only streams of the requested type instead of the overall index
2025-04-05 21:50:45 +02:00
pSelf - > psmf . currentStream = streams ; // LLE always sets this to the first stream
2024-02-29 21:45:28 +01:00
return not_an_error ( i ) ;
2014-01-18 00:45:07 +01:00
}
2014-12-11 20:25:11 +01:00
}
2024-02-29 21:45:28 +01:00
}
else
{
const auto streams = pSelf - > pamf . currentGroup . ptr ( & PamfGroup : : streams ) ;
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
for ( u8 i = 0 ; i < stream_num ; i + + )
2014-12-11 20:25:11 +01:00
{
2024-02-29 21:45:28 +01:00
if ( pamfStreamToTypeChannel ( streams [ i ] . stream_coding_type , streams [ i ] . stream_id , streams [ i ] . private_stream_id , type , vm : : null ) ! = CELL_OK )
2014-01-18 00:45:07 +01:00
{
2024-02-29 21:45:28 +01:00
continue ;
2014-01-18 00:45:07 +01:00
}
2024-02-29 21:45:28 +01:00
found + = pamfIsSameStreamType ( * type , streamType ) ;
if ( found > streamIndex )
{
pSelf - > currentStreamIndex = i ;
pSelf - > pamf . currentStream = streams + i ;
return not_an_error ( i ) ;
}
2014-01-06 02:50:56 +01:00
}
}
return CELL_PAMF_ERROR_STREAM_NOT_FOUND ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfStreamTypeToEsFilterId ( u8 type , u8 ch , vm : : ptr < CellCodecEsFilterId > pEsFilterId )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfStreamTypeToEsFilterId(type=%d, ch=%d, pEsFilterId=*0x%x) " , type , ch , pEsFilterId ) ;
2014-12-11 20:25:11 +01:00
if ( ! pEsFilterId )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2018-08-25 14:39:00 +02:00
2024-02-29 21:45:28 +01:00
u8 stream_id = 0 ;
u8 private_stream_id = 0 ;
if ( pamfTypeChannelToStream ( type , ch , nullptr , & stream_id , & private_stream_id ) ! = CELL_OK )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
pEsFilterId - > filterIdMajor = stream_id ;
pEsFilterId - > filterIdMinor = private_stream_id ;
pEsFilterId - > supplementalInfo1 = type = = CELL_PAMF_STREAM_TYPE_AVC ;
pEsFilterId - > supplementalInfo2 = 0 ;
return CELL_OK ;
2013-09-28 04:36:57 +02:00
}
2014-12-11 20:25:11 +01:00
s32 cellPamfReaderGetStreamIndex ( vm : : ptr < CellPamfReader > pSelf )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamIndex(pSelf=*0x%x) " , pSelf ) ;
2014-01-29 21:31:09 +01:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf ) ; // Not checked on LLE
return pSelf - > currentStreamIndex ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetStreamTypeAndChannel ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < u8 > pType , vm : : ptr < u8 > pCh )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamTypeAndChannel(pSelf=*0x%x, pType=*0x%x, pCh=*0x%x " , pSelf , pType , pCh ) ;
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf ) ; // Not checked on LLE
2014-12-11 20:25:11 +01:00
2024-02-29 21:45:28 +01:00
if ( pSelf - > isPsmf )
{
const auto stream = pSelf - > psmf . currentStream ;
return pamfStreamToTypeChannel ( PAMF_STREAM_CODING_TYPE_PSMF , stream - > stream_id , stream - > private_stream_id , pType , pCh ) ;
}
else
{
const auto stream = pSelf - > pamf . currentStream ;
return pamfStreamToTypeChannel ( stream - > stream_coding_type , stream - > stream_id , stream - > private_stream_id , pType , pCh ) ;
}
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetEsFilterId ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < CellCodecEsFilterId > pEsFilterId )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetEsFilterId(pSelf=*0x%x, pEsFilterId=*0x%x) " , pSelf , pEsFilterId ) ;
2014-01-18 00:45:07 +01:00
2014-12-11 20:25:11 +01:00
// always returns CELL_OK
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf & & ! ! pEsFilterId ) ; // Not checked on LLE
if ( pSelf - > isPsmf )
{
pEsFilterId - > filterIdMajor = pSelf - > psmf . currentStream - > stream_id ;
pEsFilterId - > filterIdMinor = pSelf - > psmf . currentStream - > private_stream_id ;
pEsFilterId - > supplementalInfo1 = 0 ;
}
else
{
pEsFilterId - > filterIdMajor = pSelf - > pamf . currentStream - > stream_id ;
pEsFilterId - > filterIdMinor = pSelf - > pamf . currentStream - > private_stream_id ;
pEsFilterId - > supplementalInfo1 = pSelf - > pamf . currentStream - > stream_coding_type = = PAMF_STREAM_CODING_TYPE_AVC ;
}
2014-12-11 20:25:11 +01:00
pEsFilterId - > supplementalInfo2 = 0 ;
return CELL_OK ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetStreamInfo ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < void > pInfo , u32 size )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(pSelf=*0x%x, pInfo=*0x%x, size=%d) " , pSelf , pInfo , size ) ;
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf ) ; // Not checked on LLE
2014-01-18 00:45:07 +01:00
2024-02-29 21:45:28 +01:00
const auto & header = * pSelf - > pamf . currentStream ;
const auto & psmf_header = * pSelf - > psmf . currentStream ;
const vm : : var < u8 > type ;
error_code ret ;
if ( pSelf - > isPsmf )
{
ret = pamfStreamToTypeChannel ( PAMF_STREAM_CODING_TYPE_PSMF , psmf_header . stream_id , psmf_header . private_stream_id , type , vm : : null ) ;
}
else
{
ret = pamfStreamToTypeChannel ( header . stream_coding_type , header . stream_id , header . private_stream_id , type , vm : : null ) ;
}
if ( ret ! = CELL_OK )
{
return CELL_PAMF_ERROR_INVALID_PAMF ;
}
switch ( * type )
2014-01-06 02:50:56 +01:00
{
2014-01-18 00:45:07 +01:00
case CELL_PAMF_STREAM_TYPE_AVC :
2014-12-13 17:54:01 +01:00
{
if ( size < sizeof ( CellPamfAvcInfo ) )
2014-01-06 17:16:11 +01:00
{
2014-12-13 17:54:01 +01:00
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-01-18 00:45:07 +01:00
2015-07-11 01:38:40 +02:00
auto info = vm : : static_ptr_cast < CellPamfAvcInfo > ( pInfo ) ;
2014-01-06 17:16:11 +01:00
2014-12-13 17:54:01 +01:00
info - > profileIdc = header . AVC . profileIdc ;
info - > levelIdc = header . AVC . levelIdc ;
info - > frameMbsOnlyFlag = ( header . AVC . x2 & 0x80 ) > > 7 ;
info - > videoSignalInfoFlag = ( header . AVC . x2 & 0x40 ) > > 6 ;
info - > frameRateInfo = ( header . AVC . x2 & 0x0f ) - 1 ;
info - > aspectRatioIdc = header . AVC . aspectRatioIdc ;
2014-01-18 00:45:07 +01:00
2014-12-13 17:54:01 +01:00
if ( header . AVC . aspectRatioIdc = = 0xff )
{
2024-02-29 21:45:28 +01:00
info - > sarWidth = header . AVC . sarWidth ;
info - > sarHeight = header . AVC . sarHeight ;
2014-12-13 17:54:01 +01:00
}
else
{
info - > sarWidth = 0 ;
info - > sarHeight = 0 ;
}
2014-01-18 00:45:07 +01:00
2019-12-02 22:31:34 +01:00
info - > horizontalSize = ( header . AVC . horizontalSize & u8 { 0xff } ) * 16 ;
info - > verticalSize = ( header . AVC . verticalSize & u8 { 0xff } ) * 16 ;
2014-12-13 17:54:01 +01:00
info - > frameCropLeftOffset = header . AVC . frameCropLeftOffset ;
info - > frameCropRightOffset = header . AVC . frameCropRightOffset ;
info - > frameCropTopOffset = header . AVC . frameCropTopOffset ;
info - > frameCropBottomOffset = header . AVC . frameCropBottomOffset ;
2014-01-18 00:45:07 +01:00
2014-12-13 17:54:01 +01:00
if ( info - > videoSignalInfoFlag )
{
info - > videoFormat = header . AVC . x14 > > 5 ;
info - > videoFullRangeFlag = ( header . AVC . x14 & 0x10 ) > > 4 ;
info - > colourPrimaries = header . AVC . colourPrimaries ;
info - > transferCharacteristics = header . AVC . transferCharacteristics ;
info - > matrixCoefficients = header . AVC . matrixCoefficients ;
2014-01-06 17:16:11 +01:00
}
2014-12-13 17:54:01 +01:00
else
{
info - > videoFormat = 0 ;
info - > videoFullRangeFlag = 0 ;
info - > colourPrimaries = 0 ;
info - > transferCharacteristics = 0 ;
info - > matrixCoefficients = 0 ;
}
2018-08-25 14:39:00 +02:00
2014-12-13 17:54:01 +01:00
info - > entropyCodingModeFlag = ( header . AVC . x18 & 0x80 ) > > 7 ;
info - > deblockingFilterFlag = ( header . AVC . x18 & 0x40 ) > > 6 ;
info - > minNumSlicePerPictureIdc = ( header . AVC . x18 & 0x30 ) > > 4 ;
info - > nfwIdc = header . AVC . x18 & 0x03 ;
info - > maxMeanBitrate = header . AVC . maxMeanBitrate ;
2016-01-12 22:57:16 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AVC " ) ;
2014-01-06 17:16:11 +01:00
break ;
2014-12-13 17:54:01 +01:00
}
2018-08-25 14:39:00 +02:00
2014-01-18 00:45:07 +01:00
case CELL_PAMF_STREAM_TYPE_M2V :
2014-12-13 17:54:01 +01:00
{
if ( size < sizeof ( CellPamfM2vInfo ) )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2015-07-11 01:38:40 +02:00
auto info = vm : : static_ptr_cast < CellPamfM2vInfo > ( pInfo ) ;
2014-12-13 17:54:01 +01:00
switch ( header . M2V . x0 )
{
case 0x44 : info - > profileAndLevelIndication = 3 ; break ;
case 0x48 : info - > profileAndLevelIndication = 1 ; break ;
default : info - > profileAndLevelIndication = CELL_PAMF_M2V_UNKNOWN ;
}
info - > progressiveSequence = ( header . M2V . x2 & 0x80 ) > > 7 ;
info - > videoSignalInfoFlag = ( header . M2V . x2 & 0x40 ) > > 6 ;
info - > frameRateInfo = header . M2V . x2 & 0xf ;
info - > aspectRatioIdc = header . M2V . aspectRatioIdc ;
if ( header . M2V . aspectRatioIdc = = 0xff )
{
info - > sarWidth = header . M2V . sarWidth ;
info - > sarHeight = header . M2V . sarHeight ;
}
else
{
info - > sarWidth = 0 ;
info - > sarHeight = 0 ;
}
2019-12-02 22:31:34 +01:00
info - > horizontalSize = ( header . M2V . horizontalSize & u8 { 0xff } ) * 16 ;
info - > verticalSize = ( header . M2V . verticalSize & u8 { 0xff } ) * 16 ;
2014-12-13 17:54:01 +01:00
info - > horizontalSizeValue = header . M2V . horizontalSizeValue ;
info - > verticalSizeValue = header . M2V . verticalSizeValue ;
if ( info - > videoSignalInfoFlag )
{
info - > videoFormat = header . M2V . x14 > > 5 ;
info - > videoFullRangeFlag = ( header . M2V . x14 & 0x10 ) > > 4 ;
info - > colourPrimaries = header . M2V . colourPrimaries ;
info - > transferCharacteristics = header . M2V . transferCharacteristics ;
info - > matrixCoefficients = header . M2V . matrixCoefficients ;
}
else
2014-01-18 00:45:07 +01:00
{
2014-12-13 17:54:01 +01:00
info - > videoFormat = 0 ;
info - > videoFullRangeFlag = 0 ;
info - > colourPrimaries = 0 ;
info - > transferCharacteristics = 0 ;
info - > matrixCoefficients = 0 ;
2014-01-18 00:45:07 +01:00
}
2014-12-13 17:54:01 +01:00
2016-01-12 22:57:16 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_M2V " ) ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-13 17:54:01 +01:00
}
2018-08-25 14:39:00 +02:00
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS :
2014-12-13 17:54:01 +01:00
{
if ( size < sizeof ( CellPamfAtrac3plusInfo ) )
2014-01-18 00:45:07 +01:00
{
2014-12-13 17:54:01 +01:00
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-01-18 00:45:07 +01:00
2015-07-11 01:38:40 +02:00
auto info = vm : : static_ptr_cast < CellPamfAtrac3plusInfo > ( pInfo ) ;
2014-12-13 17:54:01 +01:00
info - > samplingFrequency = header . audio . freq & 0xf ;
info - > numberOfChannels = header . audio . channels & 0xf ;
2014-01-18 00:45:07 +01:00
2016-01-12 22:57:16 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_ATRAC3PLUS " ) ;
2014-12-13 17:54:01 +01:00
break ;
}
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM :
{
if ( size < sizeof ( CellPamfLpcmInfo ) )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
2014-01-18 00:45:07 +01:00
}
2014-12-13 17:54:01 +01:00
2015-07-11 01:38:40 +02:00
auto info = vm : : static_ptr_cast < CellPamfLpcmInfo > ( pInfo ) ;
2014-12-13 17:54:01 +01:00
info - > samplingFrequency = header . audio . freq & 0xf ;
info - > numberOfChannels = header . audio . channels & 0xf ;
info - > bitsPerSample = header . audio . bps > > 6 ;
2016-01-12 22:57:16 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_PAMF_LPCM " ) ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-13 17:54:01 +01:00
}
2014-01-18 00:45:07 +01:00
case CELL_PAMF_STREAM_TYPE_AC3 :
2014-12-13 17:54:01 +01:00
{
if ( size < sizeof ( CellPamfAc3Info ) )
2014-01-18 00:45:07 +01:00
{
2014-12-13 17:54:01 +01:00
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-01-18 00:45:07 +01:00
2015-07-11 01:38:40 +02:00
auto info = vm : : static_ptr_cast < CellPamfAc3Info > ( pInfo ) ;
2014-01-18 00:45:07 +01:00
2014-12-13 17:54:01 +01:00
info - > samplingFrequency = header . audio . freq & 0xf ;
info - > numberOfChannels = header . audio . channels & 0xf ;
2016-01-12 22:57:16 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AC3 " ) ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-13 17:54:01 +01:00
}
2014-01-18 00:45:07 +01:00
2014-12-13 17:54:01 +01:00
case CELL_PAMF_STREAM_TYPE_USER_DATA :
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_USER_DATA :
2014-12-13 17:54:01 +01:00
{
2016-01-12 22:57:16 +01:00
cellPamf . error ( " cellPamfReaderGetStreamInfo(): invalid type CELL_PAMF_STREAM_TYPE_USER_DATA " ) ;
2014-12-13 17:54:01 +01:00
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-01-18 00:45:07 +01:00
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_AVC :
2014-12-13 17:54:01 +01:00
{
if ( size < 4 )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-01-18 00:45:07 +01:00
2024-02-29 21:45:28 +01:00
vm : : static_ptr_cast < u16 > ( pInfo ) [ 0 ] = psmf_header . video . horizontalSize * 0x10 ;
vm : : static_ptr_cast < u16 > ( pInfo ) [ 1 ] = psmf_header . video . verticalSize * 0x10 ;
2014-12-13 17:54:01 +01:00
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_PSMF_AVC " ) ;
2014-01-18 00:45:07 +01:00
break ;
2014-12-13 17:54:01 +01:00
}
2024-02-29 21:45:28 +01:00
case CELL_PAMF_STREAM_TYPE_PSMF_ATRAC3PLUS :
case CELL_PAMF_STREAM_TYPE_PSMF_LPCM :
2014-12-13 17:54:01 +01:00
{
if ( size < 2 )
2014-01-18 00:45:07 +01:00
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
2014-12-13 17:54:01 +01:00
2024-02-29 21:45:28 +01:00
vm : : static_ptr_cast < u8 > ( pInfo ) [ 0 ] = psmf_header . audio . channelConfiguration ;
vm : : static_ptr_cast < u8 > ( pInfo ) [ 1 ] = psmf_header . audio . samplingFrequency & 0x0f ;
2014-12-13 17:54:01 +01:00
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetStreamInfo(): PSMF audio " ) ;
break ;
2014-12-13 17:54:01 +01:00
}
default :
{
// invalid type or getting type/ch failed
2024-02-29 21:45:28 +01:00
cellPamf . error ( " cellPamfReaderGetStreamInfo(): invalid type %d " , * type ) ;
2014-12-13 17:54:01 +01:00
return CELL_PAMF_ERROR_INVALID_PAMF ;
}
2014-01-06 02:50:56 +01:00
}
2018-08-25 14:39:00 +02:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2014-12-11 20:25:11 +01:00
u32 cellPamfReaderGetNumberOfEp ( vm : : ptr < CellPamfReader > pSelf )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetNumberOfEp(pSelf=*0x%x) " , pSelf ) ;
2014-01-06 02:50:56 +01:00
2024-02-29 21:45:28 +01:00
ensure ( ! ! pSelf ) ; // Not checked on LLE
return pSelf - > isPsmf ? pSelf - > psmf . currentStream - > ep_num : pSelf - > pamf . currentStream - > ep_num ;
2013-09-28 04:36:57 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetEpIteratorWithIndex ( vm : : ptr < CellPamfReader > pSelf , u32 epIndex , vm : : ptr < CellPamfEpIterator > pIt )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetEpIteratorWithIndex(pSelf=*0x%x, epIndex=%d, pIt=*0x%x) " , pSelf , epIndex , pIt ) ;
ensure ( ! ! pSelf & & ! ! pIt ) ; // Not checked on LLE
const u32 ep_num = cellPamfReaderGetNumberOfEp ( pSelf ) ;
if ( epIndex > = ep_num )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
if ( pSelf - > attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER )
{
return CELL_PAMF_ERROR_NOT_AVAILABLE ;
}
pIt - > isPamf = ! pSelf - > isPsmf ;
pIt - > index = epIndex ;
pIt - > num = ep_num ;
2025-04-05 21:50:45 +02:00
pIt - > pCur . set ( pSelf - > isPsmf ? pSelf - > psmf . header . addr ( ) + pSelf - > psmf . currentStream - > ep_offset + epIndex * sizeof ( PsmfEpHeader ) : pSelf - > pamf . header . addr ( ) + pSelf - > pamf . currentStream - > ep_offset + epIndex * sizeof ( PamfEpHeader ) ) ;
2014-01-06 02:50:56 +01:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellPamfReaderGetEpIteratorWithTimeStamp ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < CellCodecTimeStamp > pTimeStamp , vm : : ptr < CellPamfEpIterator > pIt )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=*0x%x, pTimeStamp=*0x%x, pIt=*0x%x) " , pSelf , pTimeStamp , pIt ) ;
ensure ( ! ! pSelf & & ! ! pTimeStamp & & ! ! pIt ) ; // Not checked on LLE
if ( pSelf - > attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER )
{
return CELL_PAMF_ERROR_NOT_AVAILABLE ;
}
const u32 ep_num = cellPamfReaderGetNumberOfEp ( pSelf ) ;
pIt - > num = ep_num ;
pIt - > isPamf = ! pSelf - > isPsmf ;
if ( ep_num = = 0 )
{
return CELL_PAMF_ERROR_EP_NOT_FOUND ;
}
u32 i = ep_num - 1 ;
const u64 requested_time_stamp = std : : bit_cast < be_t < u64 > > ( * pTimeStamp ) ;
if ( pSelf - > isPsmf )
{
const auto eps = vm : : cptr < PsmfEpHeader > : : make ( pSelf - > psmf . header . addr ( ) + pSelf - > psmf . currentStream - > ep_offset ) ;
for ( ; i > = 1 ; i - - ) // always output eps[0] if no other suitable ep is found
{
const u64 time_stamp = ( static_cast < u64 > ( eps [ i ] . value0 & 1 ) < < 32 ) | eps [ i ] . pts_low ;
if ( time_stamp < = requested_time_stamp )
{
break ;
}
}
pIt - > pCur = eps + i ;
}
else
{
const auto eps = vm : : cptr < PamfEpHeader > : : make ( pSelf - > pamf . header . addr ( ) + pSelf - > pamf . currentStream - > ep_offset ) ;
for ( ; i > = 1 ; i - - ) // always output eps[0] if no other suitable ep is found
{
const u64 time_stamp = ( static_cast < u64 > ( eps [ i ] . pts_high ) < < 32 ) | eps [ i ] . pts_low ;
if ( time_stamp < = requested_time_stamp )
{
break ;
}
}
pIt - > pCur = eps + i ;
}
pIt - > index = i ;
2014-01-29 21:31:09 +01:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellPamfEpIteratorGetEp ( vm : : ptr < CellPamfEpIterator > pIt , vm : : ptr < CellPamfEp > pEp )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfEpIteratorGetEp(pIt=*0x%x, pEp=*0x%x) " , pIt , pEp ) ;
2014-07-06 20:26:05 +02:00
2014-12-11 20:25:11 +01:00
// always returns CELL_OK
2024-02-29 21:45:28 +01:00
ensure ( ! ! pIt ) ; // Not checked on LLE
if ( pIt - > isPamf )
{
pamfEpUnpack ( vm : : static_ptr_cast < const PamfEpHeader > ( pIt - > pCur ) , pEp ) ;
}
else
{
psmfEpUnpack ( vm : : static_ptr_cast < const PsmfEpHeader > ( pIt - > pCur ) , pEp ) ;
}
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2014-12-11 20:25:11 +01:00
s32 cellPamfEpIteratorMove ( vm : : ptr < CellPamfEpIterator > pIt , s32 steps , vm : : ptr < CellPamfEp > pEp )
2013-09-28 04:36:57 +02:00
{
2024-02-29 21:45:28 +01:00
cellPamf . notice ( " cellPamfEpIteratorMove(pIt=*0x%x, steps=%d, pEp=*0x%x) " , pIt , steps , pEp ) ;
ensure ( ! ! pIt ) ; // Not checked on LLE
u32 new_index = pIt - > index + steps ;
if ( static_cast < s32 > ( new_index ) < 0 )
{
steps = - static_cast < s32 > ( pIt - > index ) ;
new_index = 0 ;
}
else if ( new_index > = pIt - > num )
{
steps = ( pIt - > num - pIt - > index ) - 1 ;
new_index = pIt - > index + steps ;
}
pIt - > index = new_index ;
if ( pIt - > isPamf )
{
pIt - > pCur = vm : : static_ptr_cast < const PamfEpHeader > ( pIt - > pCur ) + steps ;
if ( pEp )
{
pamfEpUnpack ( vm : : static_ptr_cast < const PamfEpHeader > ( pIt - > pCur ) , pEp ) ;
}
}
else
{
pIt - > pCur = vm : : static_ptr_cast < const PsmfEpHeader > ( pIt - > pCur ) + steps ;
if ( pEp )
{
psmfEpUnpack ( vm : : static_ptr_cast < const PsmfEpHeader > ( pIt - > pCur ) , pEp ) ;
}
}
return steps ;
}
error_code cellPamfReaderGetEpWithTimeStamp ( vm : : ptr < CellPamfReader > pSelf , vm : : ptr < CellCodecTimeStamp > pTimeStamp , vm : : ptr < CellPamfEpUnk > pEp , u32 unk )
{
cellPamf . notice ( " cellPamfReaderGetEpWithTimeStamp(pSelf=*0x%x, pTimeStamp=*0x%x, pEp=*0x%x, unk=0x%x) " , pSelf , pTimeStamp , pEp , unk ) ;
// This function is broken on LLE
ensure ( ! ! pSelf & & ! ! pTimeStamp & & ! ! pEp ) ; // Not checked on LLE
if ( pSelf - > attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER )
{
return CELL_PAMF_ERROR_NOT_AVAILABLE ;
}
const u32 ep_num = cellPamfReaderGetNumberOfEp ( pSelf ) ;
u64 next_rpn_offset = pSelf - > dataSize ;
if ( ep_num = = 0 )
{
return CELL_PAMF_ERROR_EP_NOT_FOUND ;
}
u32 i = ep_num - 1 ;
const u64 requested_time_stamp = std : : bit_cast < be_t < u64 > > ( * pTimeStamp ) ;
if ( pSelf - > isPsmf )
{
const auto eps = vm : : cptr < PsmfEpHeader > : : make ( pSelf - > psmf . header . addr ( ) + pSelf - > psmf . currentStream - > ep_offset ) ;
for ( ; i > = 1 ; i - - ) // always output eps[0] if no other suitable ep is found
{
const u64 time_stamp = ( static_cast < u64 > ( eps [ i ] . value0 & 1 ) < < 32 ) | eps [ i ] . pts_low ;
if ( time_stamp < = requested_time_stamp )
{
break ;
}
}
// LLE doesn't write the result to pEp
if ( i < ep_num - 1 )
{
next_rpn_offset = eps [ i + 1 ] . rpnOffset ;
}
}
else
{
const auto eps = vm : : cptr < PamfEpHeader > : : make ( pSelf - > pamf . header . addr ( ) + pSelf - > pamf . currentStream - > ep_offset ) ;
for ( ; i > = 1 ; i - - ) // always output eps[0] if no other suitable ep is found
{
const u64 time_stamp = ( static_cast < u64 > ( eps [ i ] . pts_high ) < < 32 ) | eps [ i ] . pts_low ;
if ( time_stamp < = requested_time_stamp )
{
break ;
}
}
// LLE doesn't write the result to pEp
if ( i < ep_num - 1 )
{
next_rpn_offset = eps [ i + 1 ] . rpnOffset ;
}
}
if ( unk = = sizeof ( CellPamfEpUnk ) )
{
pEp - > nextRpnOffset = next_rpn_offset ;
}
return CELL_OK ;
}
error_code cellPamfReaderGetEpWithIndex ( vm : : ptr < CellPamfReader > pSelf , u32 epIndex , vm : : ptr < CellPamfEpUnk > pEp , u32 unk )
{
cellPamf . notice ( " cellPamfReaderGetEpWithIndex(pSelf=*0x%x, epIndex=%d, pEp=*0x%x, unk=0x%x) " , pSelf , epIndex , pEp , unk ) ;
ensure ( ! ! pSelf & & ! ! pEp ) ; // Not checked on LLE
const u32 ep_num = cellPamfReaderGetNumberOfEp ( pSelf ) ;
u64 next_rpn_offset = pSelf - > dataSize ;
if ( epIndex > = ep_num )
{
return CELL_PAMF_ERROR_INVALID_ARG ;
}
if ( pSelf - > attribute & CELL_PAMF_ATTRIBUTE_MINIMUM_HEADER )
{
return CELL_PAMF_ERROR_NOT_AVAILABLE ;
}
if ( pSelf - > isPsmf )
{
const auto ep = vm : : cptr < PsmfEpHeader > : : make ( pSelf - > psmf . header . addr ( ) + pSelf - > psmf . currentStream - > ep_offset + epIndex * sizeof ( PsmfEpHeader ) ) ;
psmfEpUnpack ( ep , pEp . ptr ( & CellPamfEpUnk : : ep ) ) ;
if ( epIndex < ep_num - 1 )
{
next_rpn_offset = ep [ 1 ] . rpnOffset * 0x800ull ;
}
}
else
{
const auto ep = vm : : cptr < PamfEpHeader > : : make ( pSelf - > pamf . header . addr ( ) + pSelf - > pamf . currentStream - > ep_offset + epIndex * sizeof ( PamfEpHeader ) ) ;
pamfEpUnpack ( ep , pEp . ptr ( & CellPamfEpUnk : : ep ) ) ;
2014-07-06 20:26:05 +02:00
2024-02-29 21:45:28 +01:00
if ( epIndex < ep_num - 1 )
{
next_rpn_offset = ep [ 1 ] . rpnOffset * 0x800ull ;
}
}
if ( unk = = sizeof ( CellPamfEpUnk ) )
{
pEp - > nextRpnOffset = next_rpn_offset ;
}
return CELL_OK ;
2013-09-28 04:36:57 +02:00
}
2016-03-21 20:43:03 +01:00
DECLARE ( ppu_module_manager : : cellPamf ) ( " cellPamf " , [ ] ( )
2025-04-05 21:50:45 +02:00
{
REG_FUNC ( cellPamf , cellPamfGetHeaderSize ) ;
REG_FUNC ( cellPamf , cellPamfGetHeaderSize2 ) ;
REG_FUNC ( cellPamf , cellPamfGetStreamOffsetAndSize ) ;
REG_FUNC ( cellPamf , cellPamfVerify ) ;
REG_FUNC ( cellPamf , cellPamfReaderInitialize ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetPresentationStartTime ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetPresentationEndTime ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetMuxRateBound ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetNumberOfStreams ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetNumberOfSpecificStreams ) ;
REG_FUNC ( cellPamf , cellPamfReaderSetStreamWithIndex ) ;
REG_FUNC ( cellPamf , cellPamfReaderSetStreamWithTypeAndChannel ) ;
REG_FUNC ( cellPamf , cellPamfReaderSetStreamWithTypeAndIndex ) ;
REG_FUNC ( cellPamf , cellPamfStreamTypeToEsFilterId ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetStreamIndex ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetStreamTypeAndChannel ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetEsFilterId ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetStreamInfo ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetNumberOfEp ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetEpIteratorWithIndex ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetEpIteratorWithTimeStamp ) ;
REG_FUNC ( cellPamf , cellPamfEpIteratorGetEp ) ;
REG_FUNC ( cellPamf , cellPamfEpIteratorMove ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetEpWithTimeStamp ) ;
REG_FUNC ( cellPamf , cellPamfReaderGetEpWithIndex ) ;
} ) ;