2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2015-03-06 23:58:42 +01:00
# include "Emu/IdManager.h"
2021-02-01 12:46:10 +01:00
# include "Emu/perf_meter.hpp"
2016-03-21 20:43:03 +01:00
# include "Emu/Cell/PPUModule.h"
2017-02-06 19:36:46 +01:00
# include "Emu/Cell/lv2/sys_sync.h"
2017-10-01 03:40:51 +02:00
# include "Emu/Cell/lv2/sys_ppu_thread.h"
2020-02-01 13:14:06 +01:00
# include "Emu/Cell/lv2/sys_process.h"
2024-03-27 13:44:33 +01:00
# include "Emu/savestate_utils.hpp"
2017-10-01 03:40:51 +02:00
# include "sysPrxForUser.h"
2022-04-20 23:44:22 +02:00
# include "util/media_utils.h"
2013-09-28 04:36:57 +02:00
2019-12-04 21:56:19 +01:00
# ifdef _MSC_VER
# pragma warning(push, 0)
# else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wall"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wold-style-cast"
# endif
2014-02-26 08:51:00 +01:00
extern " C "
{
2014-03-06 12:50:45 +01:00
# include "libavcodec/avcodec.h"
# include "libavutil/imgutils.h"
2015-04-17 15:24:22 +02:00
# include "libswscale/swscale.h"
2014-02-26 08:51:00 +01:00
}
2019-12-04 21:56:19 +01:00
# ifdef _MSC_VER
# pragma warning(pop)
# else
# pragma GCC diagnostic pop
# endif
2014-02-26 08:51:00 +01:00
2014-08-23 22:40:04 +02:00
# include "cellPamf.h"
2014-02-27 19:25:32 +01:00
# include "cellVdec.h"
2016-07-27 23:43:22 +02:00
# include <mutex>
# include <queue>
2017-01-26 22:34:54 +01:00
# include <cmath>
2018-10-11 00:17:19 +02:00
# include "Utilities/lockless.h"
# include <variant>
2020-12-18 15:43:34 +01:00
# include "util/asm.hpp"
2016-07-27 23:43:22 +02:00
std : : mutex g_mutex_avcodec_open2 ;
2016-05-13 15:55:34 +02:00
2018-08-25 14:39:00 +02:00
LOG_CHANNEL ( cellVdec ) ;
2016-03-21 20:43:03 +01:00
2019-09-08 17:13:58 +02:00
template < >
void fmt_class_string < CellVdecError > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
switch ( error )
{
STR_CASE ( CELL_VDEC_ERROR_ARG ) ;
STR_CASE ( CELL_VDEC_ERROR_SEQ ) ;
STR_CASE ( CELL_VDEC_ERROR_BUSY ) ;
STR_CASE ( CELL_VDEC_ERROR_EMPTY ) ;
STR_CASE ( CELL_VDEC_ERROR_AU ) ;
STR_CASE ( CELL_VDEC_ERROR_PIC ) ;
STR_CASE ( CELL_VDEC_ERROR_FATAL ) ;
}
return unknown ;
} ) ;
}
2022-04-10 12:32:01 +02:00
// The general sequence control flow has these possible transitions:
// closed -> dormant
// dormant -> ready
// dormant -> closed
// ready -> ending
// ready -> resetting
// ready -> closed
// ending -> dormant
// resetting -> ready
enum class sequence_state : u32
{
closed = 0 , // Also called non-existent. Needs to be opened before anything can be done with it.
dormant = 1 , // Waiting for the next sequence. The last picture and pic-item can be aqcuired in this state.
ready = 2 , // Ready for decoding. Can also restart sequences in this state.
ending = 3 , // Ending a sequence. Goes to dormant afterwards.
resetting = 4 , // Stops the current sequence and starts a new one. The pictures of the old sequence are flushed
invalid = 5 , // Any other value is invalid
} ;
2013-09-28 04:36:57 +02:00
2022-04-10 12:32:01 +02:00
template < >
void fmt_class_string < sequence_state > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
switch ( error )
{
STR_CASE ( sequence_state : : closed ) ;
STR_CASE ( sequence_state : : dormant ) ;
STR_CASE ( sequence_state : : ready ) ;
STR_CASE ( sequence_state : : ending ) ;
STR_CASE ( sequence_state : : resetting ) ;
STR_CASE ( sequence_state : : invalid ) ;
}
return unknown ;
} ) ;
}
vm : : gvar < s32 > _cell_vdec_prx_ver ; // TODO: this should probably specify the VDEC module that was loaded. E.g. CELL_SYSMODULE_VDEC_MPEG2
enum class vdec_cmd_type : u32
{
start_sequence ,
end_sequence ,
close ,
au_decode ,
framerate ,
} ;
2014-08-26 18:45:43 +02:00
2018-10-11 00:17:19 +02:00
struct vdec_cmd
{
2022-04-24 13:14:19 +02:00
explicit vdec_cmd ( vdec_cmd_type _type , u64 _seq_id , u64 _id )
: type ( _type ) , seq_id ( _seq_id ) , id ( _id )
2022-04-10 12:32:01 +02:00
{
ensure ( _type ! = vdec_cmd_type : : au_decode ) ;
ensure ( _type ! = vdec_cmd_type : : framerate ) ;
}
2022-04-24 13:14:19 +02:00
explicit vdec_cmd ( vdec_cmd_type _type , u64 _seq_id , u64 _id , s32 _mode , CellVdecAuInfo _au )
: type ( _type ) , seq_id ( _seq_id ) , id ( _id ) , mode ( _mode ) , au ( std : : move ( _au ) )
2022-04-10 12:32:01 +02:00
{
ensure ( _type = = vdec_cmd_type : : au_decode ) ;
}
2022-04-24 13:14:19 +02:00
explicit vdec_cmd ( vdec_cmd_type _type , u64 _seq_id , u64 _id , s32 _framerate )
: type ( _type ) , seq_id ( _seq_id ) , id ( _id ) , framerate ( _framerate )
2022-04-10 12:32:01 +02:00
{
ensure ( _type = = vdec_cmd_type : : framerate ) ;
}
vdec_cmd_type type { } ;
2022-04-24 13:14:19 +02:00
u64 seq_id { } ;
2022-04-23 18:25:00 +02:00
u64 id { } ;
2022-04-10 12:32:01 +02:00
s32 mode { } ;
s32 framerate { } ;
CellVdecAuInfo au { } ;
2016-07-27 23:43:22 +02:00
} ;
struct vdec_frame
{
struct frame_dtor
2014-12-09 17:13:03 +01:00
{
2016-07-27 23:43:22 +02:00
void operator ( ) ( AVFrame * data ) const
{
av_frame_unref ( data ) ;
av_frame_free ( & data ) ;
}
} ;
2022-04-24 13:14:19 +02:00
u64 seq_id { } ;
2022-04-23 18:25:00 +02:00
u64 cmd_id { } ;
2016-07-27 23:43:22 +02:00
std : : unique_ptr < AVFrame , frame_dtor > avf ;
2019-12-26 21:01:48 +01:00
u64 dts { } ;
u64 pts { } ;
u64 userdata { } ;
u32 frc { } ;
2022-04-12 01:31:57 +02:00
bool pic_item_received = false ;
CellVdecPicAttr attr = CELL_VDEC_PICITEM_ATTR_NORMAL ;
2016-07-27 23:43:22 +02:00
AVFrame * operator - > ( ) const
2014-12-09 17:13:03 +01:00
{
2016-07-27 23:43:22 +02:00
return avf . get ( ) ;
2014-12-09 17:13:03 +01:00
}
2016-07-27 23:43:22 +02:00
} ;
2014-12-09 17:13:03 +01:00
2018-10-11 00:17:19 +02:00
struct vdec_context final
2016-07-27 23:43:22 +02:00
{
2019-07-27 12:59:17 +02:00
static const u32 id_base = 0xf0000000 ;
static const u32 id_step = 0x00000100 ;
static const u32 id_count = 1024 ;
2022-07-04 15:02:17 +02:00
SAVESTATE_INIT_POS ( 24 ) ;
2018-10-11 00:17:19 +02:00
2022-04-23 10:31:30 +02:00
u32 handle = 0 ;
2022-04-24 13:14:19 +02:00
atomic_t < u64 > seq_id = 0 ; // The first sequence will have the ID 1
2022-04-23 18:25:00 +02:00
atomic_t < u64 > next_cmd_id = 0 ;
2022-04-10 12:32:01 +02:00
atomic_t < bool > abort_decode = false ; // Used for thread interaction
atomic_t < bool > is_running = false ; // Used for thread interaction
atomic_t < sequence_state > seq_state = sequence_state : : closed ;
2022-01-21 17:17:23 +01:00
const AVCodec * codec { } ;
2016-07-27 23:43:22 +02:00
AVCodecContext * ctx { } ;
2017-11-24 19:56:51 +01:00
SwsContext * sws { } ;
2016-07-27 23:43:22 +02:00
2018-10-11 00:17:19 +02:00
shared_mutex mutex ; // Used for 'out' queue (TODO)
const u32 type ;
2016-07-27 23:43:22 +02:00
const u32 mem_addr ;
const u32 mem_size ;
const vm : : ptr < CellVdecCbMsg > cb_func ;
const u32 cb_arg ;
u32 mem_bias { } ;
u32 frc_set { } ; // Frame Rate Override
2017-01-26 22:34:54 +01:00
u64 next_pts { } ;
u64 next_dts { } ;
2020-03-15 11:42:54 +01:00
atomic_t < u32 > ppu_tid { } ;
2016-07-27 23:43:22 +02:00
2022-04-10 12:32:01 +02:00
std : : deque < vdec_frame > out_queue ;
const u32 out_max = 60 ;
2016-07-27 23:43:22 +02:00
2023-02-05 13:02:51 +01:00
atomic_t < s32 > au_count { 0 } ;
2017-10-01 03:40:51 +02:00
2022-04-10 12:32:01 +02:00
lf_queue < vdec_cmd > in_cmd ;
2018-10-11 00:17:19 +02:00
2021-05-29 10:23:28 +02:00
AVRational log_time_base { } ; // Used to reduce log spam
2021-03-05 20:05:37 +01:00
vdec_context ( s32 type , u32 /*profile*/ , u32 addr , u32 size , vm : : ptr < CellVdecCbMsg > func , u32 arg )
2018-10-11 00:17:19 +02:00
: type ( type )
2016-07-27 23:43:22 +02:00
, mem_addr ( addr )
, mem_size ( size )
, cb_func ( func )
, cb_arg ( arg )
2014-08-23 22:40:04 +02:00
{
2016-07-27 23:43:22 +02:00
switch ( type )
{
case CELL_VDEC_CODEC_TYPE_MPEG2 :
{
codec = avcodec_find_decoder ( AV_CODEC_ID_MPEG2VIDEO ) ;
break ;
}
case CELL_VDEC_CODEC_TYPE_AVC :
{
codec = avcodec_find_decoder ( AV_CODEC_ID_H264 ) ;
break ;
}
case CELL_VDEC_CODEC_TYPE_DIVX :
{
codec = avcodec_find_decoder ( AV_CODEC_ID_MPEG4 ) ;
break ;
}
default :
{
2020-12-09 16:04:52 +01:00
fmt : : throw_exception ( " Unknown video decoder type (0x%x) " , type ) ;
2016-07-27 23:43:22 +02:00
}
}
2016-07-22 14:54:35 +02:00
2016-07-27 23:43:22 +02:00
if ( ! codec )
{
2020-12-09 16:04:52 +01:00
fmt : : throw_exception ( " avcodec_find_decoder() failed (type=0x%x) " , type ) ;
2016-07-27 23:43:22 +02:00
}
2016-07-22 14:54:35 +02:00
2016-07-27 23:43:22 +02:00
ctx = avcodec_alloc_context3 ( codec ) ;
2016-07-22 14:54:35 +02:00
2016-07-27 23:43:22 +02:00
if ( ! ctx )
{
2020-12-09 16:04:52 +01:00
fmt : : throw_exception ( " avcodec_alloc_context3() failed (type=0x%x) " , type ) ;
2016-07-27 23:43:22 +02:00
}
2016-07-22 14:54:35 +02:00
2022-04-24 09:23:37 +02:00
AVDictionary * opts = nullptr ;
2014-08-23 22:40:04 +02:00
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( g_mutex_avcodec_open2 ) ;
2016-07-27 23:43:22 +02:00
2022-04-24 09:23:37 +02:00
int err = avcodec_open2 ( ctx , codec , & opts ) ;
2016-07-27 23:43:22 +02:00
if ( err | | opts )
{
avcodec_free_context ( & ctx ) ;
2022-04-20 23:44:22 +02:00
std : : string dict_content ;
if ( opts )
{
AVDictionaryEntry * tag = nullptr ;
while ( ( tag = av_dict_get ( opts , " " , tag , AV_DICT_IGNORE_SUFFIX ) ) )
{
fmt : : append ( dict_content , " ['%s': '%s'] " , tag - > key , tag - > value ) ;
}
}
fmt : : throw_exception ( " avcodec_open2() failed (err=0x%x='%s', opts=%s) " , err , utils : : av_error_to_string ( err ) , dict_content ) ;
2016-07-27 23:43:22 +02:00
}
2022-04-10 12:32:01 +02:00
2022-04-12 22:25:21 +02:00
av_dict_free ( & opts ) ;
2022-04-10 12:32:01 +02:00
seq_state = sequence_state : : dormant ;
2014-10-18 00:20:03 +02:00
}
2016-07-22 14:54:35 +02:00
2018-10-11 00:17:19 +02:00
~ vdec_context ( )
2014-08-23 22:40:04 +02:00
{
2016-07-22 14:54:35 +02:00
avcodec_free_context ( & ctx ) ;
2017-11-24 19:56:51 +01:00
sws_freeContext ( sws ) ;
2014-03-02 00:50:47 +01:00
}
2018-10-11 00:17:19 +02:00
void exec ( ppu_thread & ppu , u32 vid )
2014-02-27 19:25:32 +01:00
{
2021-02-01 12:46:10 +01:00
perf_meter < " VDEC " _u32 > perf0 ;
2020-03-15 11:42:54 +01:00
ppu_tid . release ( ppu . id ) ;
2014-02-27 19:25:32 +01:00
2022-04-10 12:32:01 +02:00
for ( auto slice = in_cmd . pop_all ( ) ; thread_ctrl : : state ( ) ! = thread_state : : aborting ; [ & ]
2014-02-27 19:25:32 +01:00
{
2021-02-01 12:46:10 +01:00
if ( slice )
{
slice . pop_front ( ) ;
}
if ( slice | | thread_ctrl : : state ( ) = = thread_state : : aborting )
{
return ;
}
2023-07-31 22:57:26 +02:00
thread_ctrl : : wait_on ( in_cmd ) ;
2021-02-01 12:46:10 +01:00
slice = in_cmd . pop_all ( ) ; // Pop new command list
} ( ) )
{
// pcmd can be nullptr
2022-04-10 12:32:01 +02:00
auto * cmd = slice . get ( ) ;
2021-02-01 12:46:10 +01:00
2022-04-10 12:32:01 +02:00
if ( ! cmd )
2014-02-27 19:25:32 +01:00
{
2022-04-10 12:32:01 +02:00
continue ;
2018-10-11 00:17:19 +02:00
}
2022-04-10 12:32:01 +02:00
switch ( cmd - > type )
{
case vdec_cmd_type : : start_sequence :
2014-08-23 22:40:04 +02:00
{
2022-04-10 12:32:01 +02:00
std : : lock_guard lock { mutex } ;
if ( seq_state = = sequence_state : : resetting )
{
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Reset sequence... (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2022-04-10 12:32:01 +02:00
}
else
{
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Start sequence... (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2022-04-10 12:32:01 +02:00
}
2016-07-27 23:43:22 +02:00
avcodec_flush_buffers ( ctx ) ;
2014-03-03 00:02:42 +01:00
2022-04-10 12:32:01 +02:00
out_queue . clear ( ) ; // Flush image queue
2021-05-29 10:23:28 +02:00
log_time_base = { } ;
2016-07-27 23:43:22 +02:00
frc_set = 0 ; // TODO: ???
2017-01-26 22:34:54 +01:00
next_pts = 0 ;
next_dts = 0 ;
2022-04-10 12:32:01 +02:00
abort_decode = false ;
is_running = true ;
break ;
2014-08-23 22:40:04 +02:00
}
2022-04-10 12:32:01 +02:00
case vdec_cmd_type : : end_sequence :
{
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " End sequence... (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2022-04-10 12:32:01 +02:00
{
std : : lock_guard lock { mutex } ;
seq_state = sequence_state : : dormant ;
}
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Sending CELL_VDEC_MSG_TYPE_SEQDONE (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2022-04-10 12:32:01 +02:00
cb_func ( ppu , vid , CELL_VDEC_MSG_TYPE_SEQDONE , CELL_OK , cb_arg ) ;
lv2_obj : : sleep ( ppu ) ;
break ;
}
case vdec_cmd_type : : au_decode :
2014-08-23 22:40:04 +02:00
{
2016-07-22 14:54:35 +02:00
AVPacket packet { } ;
2016-07-27 23:43:22 +02:00
packet . pos = - 1 ;
2014-02-27 19:25:32 +01:00
2016-07-27 23:43:22 +02:00
u64 au_usrd { } ;
2022-04-10 12:32:01 +02:00
const u32 au_mode = cmd - > mode ;
const u32 au_addr = cmd - > au . startAddr ;
const u32 au_size = cmd - > au . size ;
const u64 au_pts = u64 { cmd - > au . pts . upper } < < 32 | cmd - > au . pts . lower ;
const u64 au_dts = u64 { cmd - > au . dts . upper } < < 32 | cmd - > au . dts . lower ;
au_usrd = cmd - > au . userData ;
2017-01-26 22:34:54 +01:00
2022-04-10 12:32:01 +02:00
packet . data = vm : : _ptr < u8 > ( au_addr ) ;
packet . size = au_size ;
packet . pts = au_pts ! = umax ? au_pts : s64 { smin } ;
packet . dts = au_dts ! = umax ? au_dts : s64 { smin } ;
2017-01-26 22:34:54 +01:00
2022-04-10 12:32:01 +02:00
if ( next_pts = = 0 & & au_pts ! = umax )
2014-08-23 22:40:04 +02:00
{
2022-04-10 12:32:01 +02:00
next_pts = au_pts ;
2014-08-23 22:40:04 +02:00
}
2014-03-04 00:21:34 +01:00
2022-04-10 12:32:01 +02:00
if ( next_dts = = 0 & & au_dts ! = umax )
2014-08-23 22:40:04 +02:00
{
2022-04-10 12:32:01 +02:00
next_dts = au_dts ;
}
2022-04-12 01:31:57 +02:00
const CellVdecPicAttr attr = au_mode = = CELL_VDEC_DEC_MODE_NORMAL ? CELL_VDEC_PICITEM_ATTR_NORMAL : CELL_VDEC_PICITEM_ATTR_SKIPPED ;
2022-04-10 12:32:01 +02:00
ctx - > skip_frame =
au_mode = = CELL_VDEC_DEC_MODE_NORMAL ? AVDISCARD_DEFAULT :
au_mode = = CELL_VDEC_DEC_MODE_B_SKIP ? AVDISCARD_NONREF : AVDISCARD_NONINTRA ;
2018-04-07 00:59:46 +02:00
2022-04-23 20:33:10 +02:00
std : : deque < vdec_frame > decoded_frames ;
2022-04-24 13:52:51 +02:00
if ( ! abort_decode & & seq_id = = cmd - > seq_id )
2022-04-10 12:32:01 +02:00
{
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " AU decoding: handle=0x%x, seq_id=%d, cmd_id=%d, size=0x%x, pts=0x%llx, dts=0x%llx, userdata=0x%llx " , handle , cmd - > seq_id , cmd - > id , au_size , au_pts , au_dts , au_usrd ) ;
2022-04-23 17:44:48 +02:00
if ( int ret = avcodec_send_packet ( ctx , & packet ) ; ret < 0 )
{
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " AU queuing error (handle=0x%x, seq_id=%d, cmd_id=%d, error=0x%x): %s " , handle , cmd - > seq_id , cmd - > id , ret , utils : : av_error_to_string ( ret ) ) ;
2022-04-23 17:44:48 +02:00
}
2022-04-24 13:52:51 +02:00
while ( ! abort_decode & & seq_id = = cmd - > seq_id )
2016-07-22 14:54:35 +02:00
{
2019-10-25 17:19:12 +02:00
// Keep receiving frames
vdec_frame frame ;
2022-04-24 13:52:51 +02:00
frame . seq_id = cmd - > seq_id ;
2022-04-23 18:25:00 +02:00
frame . cmd_id = cmd - > id ;
2019-10-25 17:19:12 +02:00
frame . avf . reset ( av_frame_alloc ( ) ) ;
2016-07-22 14:54:35 +02:00
2019-10-25 17:19:12 +02:00
if ( ! frame . avf )
{
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " av_frame_alloc() failed (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2019-10-25 17:19:12 +02:00
}
if ( int ret = avcodec_receive_frame ( ctx , frame . avf . get ( ) ) ; ret < 0 )
{
2022-04-10 12:32:01 +02:00
if ( ret = = AVERROR ( EAGAIN ) | | ret = = AVERROR ( EOF ) )
2019-10-25 17:19:12 +02:00
{
break ;
}
2022-04-12 22:25:21 +02:00
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " AU decoding error (handle=0x%x, seq_id=%d, cmd_id=%d, error=0x%x): %s " , handle , cmd - > seq_id , cmd - > id , ret , utils : : av_error_to_string ( ret ) ) ;
2019-10-25 17:19:12 +02:00
}
2016-07-27 23:43:22 +02:00
if ( frame - > interlaced_frame )
2014-12-09 17:13:03 +01:00
{
2018-03-31 16:09:30 +02:00
// NPEB01838, NPUB31260
2022-04-24 13:14:19 +02:00
cellVdec . todo ( " Interlaced frames not supported (handle=0x%x, seq_id=%d, cmd_id=%d, interlaced_frame=0x%x) " , handle , cmd - > seq_id , cmd - > id , frame - > interlaced_frame ) ;
2014-12-09 17:13:03 +01:00
}
2016-07-27 23:43:22 +02:00
if ( frame - > repeat_pict )
2014-03-03 00:02:42 +01:00
{
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " Repeated frames not supported (handle=0x%x, seq_id=%d, cmd_id=%d, repear_pict=0x%x) " , handle , cmd - > seq_id , cmd - > id , frame - > repeat_pict ) ;
2014-12-09 17:13:03 +01:00
}
2021-05-22 09:35:15 +02:00
if ( frame - > pts ! = smin )
2017-01-26 22:34:54 +01:00
{
2020-02-23 18:08:51 +01:00
next_pts = frame - > pts ;
2017-01-26 22:34:54 +01:00
}
2021-05-22 09:35:15 +02:00
if ( frame - > pkt_dts ! = smin )
2017-01-26 22:34:54 +01:00
{
next_dts = frame - > pkt_dts ;
}
frame . pts = next_pts ;
frame . dts = next_dts ;
frame . userdata = au_usrd ;
2022-04-12 01:31:57 +02:00
frame . attr = attr ;
2017-01-26 22:34:54 +01:00
2016-07-27 23:43:22 +02:00
if ( frc_set )
2014-12-09 17:13:03 +01:00
{
2016-07-22 14:54:35 +02:00
u64 amend = 0 ;
2016-07-27 23:43:22 +02:00
switch ( frc_set )
2014-12-09 17:13:03 +01:00
{
2016-07-22 14:54:35 +02:00
case CELL_VDEC_FRC_24000DIV1001 : amend = 1001 * 90000 / 24000 ; break ;
case CELL_VDEC_FRC_24 : amend = 90000 / 24 ; break ;
case CELL_VDEC_FRC_25 : amend = 90000 / 25 ; break ;
case CELL_VDEC_FRC_30000DIV1001 : amend = 1001 * 90000 / 30000 ; break ;
case CELL_VDEC_FRC_30 : amend = 90000 / 30 ; break ;
case CELL_VDEC_FRC_50 : amend = 90000 / 50 ; break ;
case CELL_VDEC_FRC_60000DIV1001 : amend = 1001 * 90000 / 60000 ; break ;
case CELL_VDEC_FRC_60 : amend = 90000 / 60 ; break ;
2014-12-09 17:13:03 +01:00
default :
{
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " Invalid frame rate code set (handle=0x%x, seq_id=%d, cmd_id=%d, frc=0x%x) " , handle , cmd - > seq_id , cmd - > id , frc_set ) ;
2014-12-09 17:13:03 +01:00
}
}
2017-01-26 22:34:54 +01:00
next_pts + = amend ;
next_dts + = amend ;
2016-07-27 23:43:22 +02:00
frame . frc = frc_set ;
2014-08-23 22:40:04 +02:00
}
2017-03-17 18:51:06 +01:00
else if ( ctx - > time_base . num = = 0 )
{
2021-05-29 10:23:28 +02:00
if ( log_time_base . den ! = ctx - > time_base . den | | log_time_base . num ! = ctx - > time_base . num )
{
2022-04-24 13:14:19 +02:00
cellVdec . error ( " time_base.num is 0 (handle=0x%x, seq_id=%d, cmd_id=%d, %d/%d, tpf=%d framerate=%d/%d) " , handle , cmd - > seq_id , cmd - > id , ctx - > time_base . num , ctx - > time_base . den , ctx - > ticks_per_frame , ctx - > framerate . num , ctx - > framerate . den ) ;
2021-05-29 10:23:28 +02:00
log_time_base = ctx - > time_base ;
}
2017-03-17 18:51:06 +01:00
// Hack
const u64 amend = u64 { 90000 } / 30 ;
frame . frc = CELL_VDEC_FRC_30 ;
next_pts + = amend ;
next_dts + = amend ;
}
2014-08-23 22:40:04 +02:00
else
{
2018-04-18 08:20:19 +02:00
u64 amend = u64 { 90000 } * ctx - > time_base . num * ctx - > ticks_per_frame / ctx - > time_base . den ;
2017-01-26 22:34:54 +01:00
const auto freq = 1. * ctx - > time_base . den / ctx - > time_base . num / ctx - > ticks_per_frame ;
if ( std : : abs ( freq - 23.976 ) < 0.002 )
frame . frc = CELL_VDEC_FRC_24000DIV1001 ;
else if ( std : : abs ( freq - 24.000 ) < 0.001 )
frame . frc = CELL_VDEC_FRC_24 ;
else if ( std : : abs ( freq - 25.000 ) < 0.001 )
frame . frc = CELL_VDEC_FRC_25 ;
else if ( std : : abs ( freq - 29.970 ) < 0.002 )
frame . frc = CELL_VDEC_FRC_30000DIV1001 ;
else if ( std : : abs ( freq - 30.000 ) < 0.001 )
frame . frc = CELL_VDEC_FRC_30 ;
else if ( std : : abs ( freq - 50.000 ) < 0.001 )
frame . frc = CELL_VDEC_FRC_50 ;
else if ( std : : abs ( freq - 59.940 ) < 0.002 )
frame . frc = CELL_VDEC_FRC_60000DIV1001 ;
else if ( std : : abs ( freq - 60.000 ) < 0.001 )
frame . frc = CELL_VDEC_FRC_60 ;
2014-12-09 17:13:03 +01:00
else
2018-04-18 08:20:19 +02:00
{
2021-05-29 10:23:28 +02:00
if ( log_time_base . den ! = ctx - > time_base . den | | log_time_base . num ! = ctx - > time_base . num )
{
// 1/1000 usually means that the time stamps are written in 1ms units and that the frame rate may vary.
2022-04-24 13:14:19 +02:00
cellVdec . error ( " Unsupported time_base (handle=0x%x, seq_id=%d, cmd_id=%d, %d/%d, tpf=%d framerate=%d/%d) " , handle , cmd - > seq_id , cmd - > id , ctx - > time_base . num , ctx - > time_base . den , ctx - > ticks_per_frame , ctx - > framerate . num , ctx - > framerate . den ) ;
2021-05-29 10:23:28 +02:00
log_time_base = ctx - > time_base ;
}
2018-04-18 08:20:19 +02:00
// Hack
amend = u64 { 90000 } / 30 ;
2018-08-25 14:39:00 +02:00
frame . frc = CELL_VDEC_FRC_30 ;
2018-04-18 08:20:19 +02:00
}
next_pts + = amend ;
next_dts + = amend ;
2014-08-23 22:40:04 +02:00
}
2014-12-09 17:13:03 +01:00
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Got picture (handle=0x%x, seq_id=%d, cmd_id=%d, pts=0x%llx[0x%llx], dts=0x%llx[0x%llx]) " , handle , cmd - > seq_id , cmd - > id , frame . pts , frame - > pts , frame . dts , frame - > pkt_dts ) ;
2014-03-19 01:32:23 +01:00
2022-04-23 20:33:10 +02:00
decoded_frames . push_back ( std : : move ( frame ) ) ;
}
}
2016-07-27 23:43:22 +02:00
2022-04-24 13:52:51 +02:00
if ( thread_ctrl : : state ( ) ! = thread_state : : aborting )
2022-04-23 20:33:10 +02:00
{
2022-04-24 13:52:51 +02:00
// Send AUDONE even if the current sequence was reset and a new sequence was started.
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Sending CELL_VDEC_MSG_TYPE_AUDONE (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2023-02-05 13:02:51 +01:00
ensure ( au_count . try_dec ( 0 ) ) ;
2022-04-23 20:33:10 +02:00
cb_func ( ppu , vid , CELL_VDEC_MSG_TYPE_AUDONE , CELL_OK , cb_arg ) ;
lv2_obj : : sleep ( ppu ) ;
2016-07-22 14:54:35 +02:00
2022-04-24 13:52:51 +02:00
while ( ! decoded_frames . empty ( ) & & seq_id = = cmd - > seq_id )
2022-04-23 20:33:10 +02:00
{
2022-04-10 12:32:01 +02:00
// Wait until there is free space in the image queue.
// Do this after pushing the frame to the queue. That way the game can consume the frame and we can move on.
u32 elapsed = 0 ;
2022-04-24 13:52:51 +02:00
while ( thread_ctrl : : state ( ) ! = thread_state : : aborting & & ! abort_decode & & seq_id = = cmd - > seq_id )
2022-04-10 12:32:01 +02:00
{
{
std : : lock_guard lock { mutex } ;
if ( out_queue . size ( ) < = out_max )
{
break ;
}
}
2022-09-07 10:19:56 +02:00
thread_ctrl : : wait_for ( 10000 ) ;
if ( elapsed + + > = 500 ) // 5 seconds
2022-04-10 12:32:01 +02:00
{
2022-04-24 13:14:19 +02:00
cellVdec . error ( " Video au decode has been waiting for a consumer for 5 seconds. (handle=0x%x, seq_id=%d, cmd_id=%d, queue_size=%d) " , handle , cmd - > seq_id , cmd - > id , out_queue . size ( ) ) ;
2022-04-10 12:32:01 +02:00
elapsed = 0 ;
}
}
2022-04-23 20:33:10 +02:00
2022-04-24 13:52:51 +02:00
if ( thread_ctrl : : state ( ) = = thread_state : : aborting | | abort_decode | | seq_id ! = cmd - > seq_id )
2022-04-23 20:33:10 +02:00
{
break ;
}
{
std : : lock_guard lock { mutex } ;
out_queue . push_back ( std : : move ( decoded_frames . front ( ) ) ) ;
decoded_frames . pop_front ( ) ;
}
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Sending CELL_VDEC_MSG_TYPE_PICOUT (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2022-04-23 20:33:10 +02:00
cb_func ( ppu , vid , CELL_VDEC_MSG_TYPE_PICOUT , CELL_OK , cb_arg ) ;
lv2_obj : : sleep ( ppu ) ;
2016-07-22 14:54:35 +02:00
}
2014-02-27 19:25:32 +01:00
}
2014-08-23 22:40:04 +02:00
2022-04-24 13:52:51 +02:00
if ( abort_decode | | seq_id ! = cmd - > seq_id )
2022-04-23 17:44:48 +02:00
{
2022-04-24 13:14:19 +02:00
cellVdec . warning ( " AU decoding: aborted (handle=0x%x, seq_id=%d, cmd_id=%d, abort_decode=%d) " , handle , cmd - > seq_id , cmd - > id , abort_decode . load ( ) ) ;
2022-04-23 17:44:48 +02:00
}
2022-04-23 20:33:10 +02:00
else
2022-04-23 17:44:48 +02:00
{
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " AU decoding: done (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , cmd - > seq_id , cmd - > id ) ;
2022-04-23 17:44:48 +02:00
}
2017-11-24 19:56:51 +01:00
2022-04-10 12:32:01 +02:00
break ;
2014-08-23 22:40:04 +02:00
}
2022-04-10 12:32:01 +02:00
case vdec_cmd_type : : framerate :
2014-08-23 22:40:04 +02:00
{
2022-04-10 12:32:01 +02:00
frc_set = cmd - > framerate ;
break ;
2014-08-23 22:40:04 +02:00
}
2022-04-10 12:32:01 +02:00
case vdec_cmd_type : : close :
{
std : : lock_guard lock { mutex } ;
out_queue . clear ( ) ;
break ;
}
default :
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " Unknown vdec_cmd_type (handle=0x%x, seq_id=%d, cmd_id=%d, type=%d) " , handle , cmd - > seq_id , cmd - > id , static_cast < u32 > ( cmd - > type ) ) ;
2022-04-10 12:32:01 +02:00
break ;
}
std : : lock_guard lock { mutex } ;
if ( seq_state = = sequence_state : : closed )
2014-12-12 01:21:34 +01:00
{
2018-10-11 00:17:19 +02:00
break ;
2014-02-27 19:25:32 +01:00
}
}
2022-04-10 12:32:01 +02:00
// Make sure the state is closed at the end
std : : lock_guard lock { mutex } ;
seq_state = sequence_state : : closed ;
2016-07-27 23:43:22 +02:00
}
} ;
2014-02-27 19:25:32 +01:00
2024-03-27 13:44:33 +01:00
extern bool check_if_vdec_contexts_exist ( )
2022-07-04 15:02:17 +02:00
{
2024-03-27 13:44:33 +01:00
bool context_exists = false ;
2022-07-04 15:02:17 +02:00
2024-03-27 13:44:33 +01:00
idm : : select < vdec_context > ( [ & ] ( u32 , vdec_context & )
2022-07-04 15:02:17 +02:00
{
2024-03-27 13:44:33 +01:00
context_exists = true ;
} ) ;
2022-07-04 15:02:17 +02:00
2024-03-27 13:44:33 +01:00
return context_exists ;
2022-07-04 15:02:17 +02:00
}
extern void vdecEntry ( ppu_thread & ppu , u32 vid )
2018-10-11 00:17:19 +02:00
{
idm : : get < vdec_context > ( vid ) - > exec ( ppu , vid ) ;
2019-08-12 06:58:13 +02:00
ppu . state + = cpu_flag : : exit ;
2018-10-11 00:17:19 +02:00
}
2020-02-01 13:14:06 +01:00
static error_code vdecQueryAttr ( s32 type , u32 profile , u32 spec_addr /* may be 0 */ , CellVdecAttr * attr )
2016-07-27 23:43:22 +02:00
{
2020-02-01 13:14:06 +01:00
// Write 0 at start
attr - > memSize = 0 ;
u32 decoderVerLower ;
u32 memSize = 0 ;
const bool new_sdk = g_ps3_process_info . sdk_ver > 0x20FFFF ;
switch ( type )
2020-01-02 16:46:52 +01:00
{
2020-02-01 13:14:06 +01:00
case CELL_VDEC_CODEC_TYPE_AVC :
{
cellVdec . warning ( " cellVdecQueryAttr: AVC (profile=%d) " , profile ) ;
2021-01-12 11:01:06 +01:00
//const vm::ptr<CellVdecAvcSpecificInfo> sinfo = vm::cast(spec_addr);
2020-02-04 21:00:36 +01:00
// TODO: sinfo
2020-02-01 13:14:06 +01:00
switch ( profile )
{
case CELL_VDEC_AVC_LEVEL_1P0 : memSize = new_sdk ? 0x70167D : 0xA014FD ; break ;
case CELL_VDEC_AVC_LEVEL_1P1 : memSize = new_sdk ? 0x86CB7D : 0xB6C9FD ; break ;
case CELL_VDEC_AVC_LEVEL_1P2 : memSize = new_sdk ? 0x9E307D : 0xCE2D7D ; break ;
case CELL_VDEC_AVC_LEVEL_1P3 : memSize = new_sdk ? 0xA057FD : 0xD054FD ; break ;
case CELL_VDEC_AVC_LEVEL_2P0 : memSize = new_sdk ? 0xA057FD : 0xD054FD ; break ;
case CELL_VDEC_AVC_LEVEL_2P1 : memSize = new_sdk ? 0xE90DFD : 0x1190AFD ; break ;
case CELL_VDEC_AVC_LEVEL_2P2 : memSize = new_sdk ? 0x14E49FD : 0x17E46FD ; break ;
case CELL_VDEC_AVC_LEVEL_3P0 : memSize = new_sdk ? 0x155B5FD : 0x185B17D ; break ;
case CELL_VDEC_AVC_LEVEL_3P1 : memSize = new_sdk ? 0x1CD327D : 0x1FD2AFD ; break ;
case CELL_VDEC_AVC_LEVEL_3P2 : memSize = new_sdk ? 0x2397B7D : 0x2696F7D ; break ;
case CELL_VDEC_AVC_LEVEL_4P0 : memSize = new_sdk ? 0x33A5FFD : 0x36A527D ; break ;
case CELL_VDEC_AVC_LEVEL_4P1 : memSize = new_sdk ? 0x33A5FFD : 0x36A527D ; break ;
case CELL_VDEC_AVC_LEVEL_4P2 : memSize = new_sdk ? 0x33A5FFD : 0x36A527D ; break ;
default : return CELL_VDEC_ERROR_ARG ;
}
decoderVerLower = 0x11300 ;
break ;
2020-01-02 16:46:52 +01:00
}
2020-02-01 13:14:06 +01:00
case CELL_VDEC_CODEC_TYPE_MPEG2 :
{
cellVdec . warning ( " cellVdecQueryAttr: MPEG2 (profile=%d) " , profile ) ;
2020-02-04 21:00:36 +01:00
const vm : : ptr < CellVdecMpeg2SpecificInfo > sinfo = vm : : cast ( spec_addr ) ;
if ( sinfo )
{
if ( sinfo - > thisSize ! = sizeof ( CellVdecMpeg2SpecificInfo ) )
{
return CELL_VDEC_ERROR_ARG ;
}
}
// TODO: sinfo
const u32 maxDecH = sinfo ? + sinfo - > maxDecodedFrameHeight : 0 ;
const u32 maxDecW = sinfo ? + sinfo - > maxDecodedFrameWidth : 0 ;
2020-02-01 13:14:06 +01:00
switch ( profile )
{
2020-02-04 21:00:36 +01:00
case CELL_VDEC_MPEG2_MP_LL :
{
if ( maxDecW > 352 | | maxDecH > 288 )
{
return CELL_VDEC_ERROR_ARG ;
}
memSize = new_sdk ? 0x11290B : 0x2A610B ;
break ;
}
case CELL_VDEC_MPEG2_MP_ML :
{
if ( maxDecW > 720 | | maxDecH > 576 )
{
return CELL_VDEC_ERROR_ARG ;
}
memSize = new_sdk ? 0x2DFB8B : 0x47110B ;
break ;
}
case CELL_VDEC_MPEG2_MP_H14 :
{
if ( maxDecW > 1440 | | maxDecH > 1152 )
{
return CELL_VDEC_ERROR_ARG ;
}
memSize = new_sdk ? 0xA0270B : 0xB8F90B ;
break ;
}
case CELL_VDEC_MPEG2_MP_HL :
{
if ( maxDecW > 1920 | | maxDecH > 1152 )
{
return CELL_VDEC_ERROR_ARG ;
}
2020-02-19 18:03:59 +01:00
2020-02-04 21:00:36 +01:00
memSize = new_sdk ? 0xD2F40B : 0xEB990B ;
break ;
}
2020-02-01 13:14:06 +01:00
default : return CELL_VDEC_ERROR_ARG ;
}
2020-01-02 16:46:52 +01:00
2020-02-01 13:14:06 +01:00
decoderVerLower = 0x1030000 ;
break ;
}
case CELL_VDEC_CODEC_TYPE_DIVX :
2016-07-27 23:43:22 +02:00
{
2020-02-01 13:14:06 +01:00
cellVdec . warning ( " cellVdecQueryAttr: DivX (profile=%d) " , profile ) ;
2022-04-12 01:32:28 +02:00
const vm : : ptr < CellVdecDivxSpecificInfo2 > sinfo = vm : : cast ( spec_addr ) ;
if ( sinfo )
{
if ( sinfo - > thisSize ! = sizeof ( CellVdecDivxSpecificInfo2 ) )
{
return CELL_VDEC_ERROR_ARG ;
}
}
2020-02-04 21:00:36 +01:00
// TODO: sinfo
2022-04-12 01:32:28 +02:00
//const u32 maxDecH = sinfo ? +sinfo->maxDecodedFrameHeight : 0;
//const u32 maxDecW = sinfo ? +sinfo->maxDecodedFrameWidth : 0;
u32 nrOfBuf = sinfo ? + sinfo - > numberOfDecodedFrameBuffer : 0 ;
if ( nrOfBuf = = 0 )
{
nrOfBuf = 4 ;
}
else if ( nrOfBuf = = 2 )
{
if ( profile ! = CELL_VDEC_DIVX_QMOBILE & & profile ! = CELL_VDEC_DIVX_MOBILE )
{
return CELL_VDEC_ERROR_ARG ;
}
}
else if ( nrOfBuf ! = 4 & & nrOfBuf ! = 3 )
{
return CELL_VDEC_ERROR_ARG ;
}
// TODO: change memSize based on buffercount.
2020-02-01 13:14:06 +01:00
switch ( profile )
{
case CELL_VDEC_DIVX_QMOBILE : memSize = new_sdk ? 0x11B720 : 0x1DEF30 ; break ;
case CELL_VDEC_DIVX_MOBILE : memSize = new_sdk ? 0x19A740 : 0x26DED0 ; break ;
case CELL_VDEC_DIVX_HOME_THEATER : memSize = new_sdk ? 0x386A60 : 0x498060 ; break ;
case CELL_VDEC_DIVX_HD_720 : memSize = new_sdk ? 0x692070 : 0x805690 ; break ;
case CELL_VDEC_DIVX_HD_1080 : memSize = new_sdk ? 0xD78100 : 0xFC9870 ; break ;
default : return CELL_VDEC_ERROR_ARG ;
}
2020-02-04 21:00:36 +01:00
2020-02-01 13:14:06 +01:00
decoderVerLower = 0x30806 ;
break ;
}
2016-07-27 23:43:22 +02:00
default : return CELL_VDEC_ERROR_ARG ;
}
2015-07-01 00:25:52 +02:00
2020-02-01 13:14:06 +01:00
attr - > decoderVerLower = decoderVerLower ;
attr - > decoderVerUpper = 0x4840010 ;
2020-12-09 08:47:45 +01:00
attr - > memSize = ! spec_addr ? ensure ( memSize ) : 4 * 1024 * 1024 ;
2017-10-01 03:40:51 +02:00
attr - > cmdDepth = 4 ;
2016-07-27 23:43:22 +02:00
return CELL_OK ;
2014-02-27 19:25:32 +01:00
}
2019-09-08 17:13:58 +02:00
error_code cellVdecQueryAttr ( vm : : cptr < CellVdecType > type , vm : : ptr < CellVdecAttr > attr )
2014-02-27 19:25:32 +01:00
{
2016-01-12 22:57:16 +01:00
cellVdec . warning ( " cellVdecQueryAttr(type=*0x%x, attr=*0x%x) " , type , attr ) ;
2014-02-27 19:25:32 +01:00
2020-01-02 16:46:52 +01:00
if ( ! type | | ! attr )
{
return CELL_VDEC_ERROR_ARG ;
}
2020-02-01 13:14:06 +01:00
return vdecQueryAttr ( type - > codecType , type - > profileLevel , 0 , attr . get_ptr ( ) ) ;
2014-02-27 19:25:32 +01:00
}
2019-09-08 17:13:58 +02:00
error_code cellVdecQueryAttrEx ( vm : : cptr < CellVdecTypeEx > type , vm : : ptr < CellVdecAttr > attr )
2013-09-28 04:36:57 +02:00
{
2016-01-12 22:57:16 +01:00
cellVdec . warning ( " cellVdecQueryAttrEx(type=*0x%x, attr=*0x%x) " , type , attr ) ;
2014-02-27 19:25:32 +01:00
2020-01-02 16:46:52 +01:00
if ( ! type | | ! attr )
{
return CELL_VDEC_ERROR_ARG ;
}
2020-02-01 13:14:06 +01:00
return vdecQueryAttr ( type - > codecType , type - > profileLevel , type - > codecSpecificInfo_addr , attr . get_ptr ( ) ) ;
2013-09-28 04:36:57 +02:00
}
2018-10-11 00:17:19 +02:00
template < typename T , typename U >
2019-09-08 17:13:58 +02:00
static error_code vdecOpen ( ppu_thread & ppu , T type , U res , vm : : cptr < CellVdecCb > cb , vm : : ptr < u32 > handle )
2013-09-28 04:36:57 +02:00
{
2022-04-10 12:32:01 +02:00
if ( ! type | | ! res | | ! cb | | ! handle | | ! cb - > cbFunc )
2019-03-11 20:31:45 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
if ( ! res - > memAddr | | res - > ppuThreadPriority + 0u > = 3072 | | res - > spuThreadPriority + 0u > = 256 | | res - > ppuThreadStackSize < 4096
| | type - > codecType + 0u > = 0xe )
2020-02-01 13:14:06 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2020-02-04 14:15:18 +01:00
u32 spec_addr = 0 ;
if constexpr ( std : : is_same_v < std : : decay_t < typename T : : type > , CellVdecTypeEx > )
{
spec_addr = type - > codecSpecificInfo_addr ;
}
2020-02-01 13:14:06 +01:00
if ( CellVdecAttr attr { } ;
2020-02-04 14:15:18 +01:00
vdecQueryAttr ( type - > codecType , type - > profileLevel , spec_addr , & attr ) ! = CELL_OK | |
2020-02-01 13:14:06 +01:00
attr . memSize > res - > memSize )
2019-03-11 20:31:45 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2018-10-11 00:17:19 +02:00
// Create decoder context
2022-07-04 15:02:17 +02:00
std : : shared_ptr < vdec_context > vdec ;
2024-03-27 13:44:33 +01:00
if ( std : : unique_lock lock { g_fxo - > get < hle_locks_t > ( ) , std : : try_to_lock } )
2022-07-04 15:02:17 +02:00
{
vdec = idm : : make_ptr < vdec_context > ( type - > codecType , type - > profileLevel , res - > memAddr , res - > memSize , cb - > cbFunc , cb - > cbArg ) ;
}
else
{
ppu . state + = cpu_flag : : again ;
return { } ;
}
const u32 vid = idm : : last_id ( ) ;
2014-02-27 19:25:32 +01:00
2022-04-23 10:31:30 +02:00
ensure ( vdec ) ;
vdec - > handle = vid ;
2018-10-11 00:17:19 +02:00
// Run thread
vm : : var < u64 > _tid ;
vm : : var < char [ ] > _name = vm : : make_str ( " HLE Video Decoder " ) ;
2019-04-11 20:03:46 +02:00
ppu_execute < & sys_ppu_thread_create > ( ppu , + _tid , 0x10000 , vid , + res - > ppuThreadPriority , + res - > ppuThreadStackSize , SYS_PPU_THREAD_CREATE_INTERRUPT , + _name ) ;
2018-10-11 00:17:19 +02:00
* handle = vid ;
2016-07-27 23:43:22 +02:00
2019-10-25 12:32:21 +02:00
const auto thrd = idm : : get < named_thread < ppu_thread > > ( static_cast < u32 > ( * _tid ) ) ;
2016-07-27 23:43:22 +02:00
2018-10-11 00:17:19 +02:00
thrd - > cmd_list
( {
{ ppu_cmd : : set_args , 1 } , u64 { vid } ,
{ ppu_cmd : : hle_call , FIND_FUNC ( vdecEntry ) } ,
} ) ;
2017-10-01 03:40:51 +02:00
2018-10-11 00:17:19 +02:00
thrd - > state - = cpu_flag : : stop ;
2023-07-31 22:57:26 +02:00
thrd - > state . notify_one ( ) ;
2014-02-27 19:25:32 +01:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2019-09-08 17:13:58 +02:00
error_code cellVdecOpen ( ppu_thread & ppu , vm : : cptr < CellVdecType > type , vm : : cptr < CellVdecResource > res , vm : : cptr < CellVdecCb > cb , vm : : ptr < u32 > handle )
2013-09-28 04:36:57 +02:00
{
2018-10-11 00:17:19 +02:00
cellVdec . warning ( " cellVdecOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x) " , type , res , cb , handle ) ;
2016-07-27 23:43:22 +02:00
2018-10-11 00:17:19 +02:00
return vdecOpen ( ppu , type , res , cb , handle ) ;
}
2017-10-01 03:40:51 +02:00
2019-09-08 17:13:58 +02:00
error_code cellVdecOpenEx ( ppu_thread & ppu , vm : : cptr < CellVdecTypeEx > type , vm : : cptr < CellVdecResourceEx > res , vm : : cptr < CellVdecCb > cb , vm : : ptr < u32 > handle )
2018-10-11 00:17:19 +02:00
{
cellVdec . warning ( " cellVdecOpenEx(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x) " , type , res , cb , handle ) ;
2014-02-27 19:25:32 +01:00
2018-10-11 00:17:19 +02:00
return vdecOpen ( ppu , type , res , cb , handle ) ;
2013-09-28 04:36:57 +02:00
}
2019-09-08 17:13:58 +02:00
error_code cellVdecClose ( ppu_thread & ppu , u32 handle )
2013-09-28 04:36:57 +02:00
{
2016-01-12 22:57:16 +01:00
cellVdec . warning ( " cellVdecClose(handle=0x%x) " , handle ) ;
2014-02-27 19:25:32 +01:00
2024-03-27 13:44:33 +01:00
std : : unique_lock lock_hle { g_fxo - > get < hle_locks_t > ( ) , std : : try_to_lock } ;
if ( ! lock_hle )
{
ppu . state + = cpu_flag : : again ;
return { } ;
}
2022-04-10 12:32:01 +02:00
auto vdec = idm : : get < vdec_context > ( handle ) ;
2015-04-12 22:16:30 +02:00
if ( ! vdec )
2014-02-27 19:25:32 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
{
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state = = sequence_state : : closed )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
}
2020-01-02 16:46:52 +01:00
2022-04-24 13:14:19 +02:00
const u64 seq_id = vdec - > seq_id ;
2022-04-23 18:25:00 +02:00
const u64 cmd_id = vdec - > next_cmd_id + + ;
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Adding close cmd (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , seq_id , cmd_id ) ;
2022-04-23 18:25:00 +02:00
2017-02-22 11:10:55 +01:00
lv2_obj : : sleep ( ppu ) ;
2022-04-10 12:32:01 +02:00
vdec - > abort_decode = true ;
2022-04-24 13:14:19 +02:00
vdec - > in_cmd . push ( vdec_cmd ( vdec_cmd_type : : close , seq_id , cmd_id ) ) ;
2019-01-13 22:03:43 +01:00
2020-03-15 11:42:54 +01:00
while ( ! vdec - > ppu_tid )
2019-01-13 22:03:43 +01:00
{
thread_ctrl : : wait_for ( 1000 ) ;
}
2020-03-15 11:42:54 +01:00
const u32 tid = vdec - > ppu_tid . exchange ( - 1 ) ;
if ( tid ! = umax )
{
ppu_execute < & sys_interrupt_thread_disestablish > ( ppu , tid ) ;
}
2020-03-14 12:27:18 +01:00
2022-04-10 12:32:01 +02:00
vdec - > seq_state = sequence_state : : closed ;
2023-02-23 21:30:01 +01:00
vdec - > mutex . lock_unlock ( ) ;
2022-04-10 12:32:01 +02:00
2023-02-23 21:30:01 +01:00
if ( ! idm : : remove_verify < vdec_context > ( handle , std : : move ( vdec ) ) )
2020-03-14 12:27:18 +01:00
{
// Other thread removed it beforehead
return CELL_VDEC_ERROR_ARG ;
}
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2022-09-07 10:19:56 +02:00
error_code cellVdecStartSeq ( ppu_thread & ppu , u32 handle )
2013-09-28 04:36:57 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2022-04-24 11:51:34 +02:00
cellVdec . warning ( " cellVdecStartSeq(handle=0x%x) " , handle ) ;
2014-02-27 19:25:32 +01:00
2018-10-11 00:17:19 +02:00
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2014-02-27 19:25:32 +01:00
2015-04-12 22:16:30 +02:00
if ( ! vdec )
2014-02-27 19:25:32 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
sequence_state old_state { } ;
{
std : : lock_guard lock { vdec - > mutex } ;
old_state = vdec - > seq_state ;
if ( old_state ! = sequence_state : : dormant & & old_state ! = sequence_state : : ready )
{
return { CELL_VDEC_ERROR_SEQ , old_state } ;
}
if ( old_state = = sequence_state : : ready )
{
vdec - > seq_state = sequence_state : : resetting ;
}
}
2022-04-24 13:14:19 +02:00
const u64 seq_id = + + vdec - > seq_id ;
2022-04-23 18:25:00 +02:00
const u64 cmd_id = vdec - > next_cmd_id + + ;
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Adding start cmd (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , seq_id , cmd_id ) ;
2022-04-23 18:25:00 +02:00
2022-04-24 13:52:51 +02:00
vdec - > abort_decode = false ;
2022-04-10 12:32:01 +02:00
vdec - > is_running = false ;
2022-04-24 13:14:19 +02:00
vdec - > in_cmd . push ( vdec_cmd ( vdec_cmd_type : : start_sequence , seq_id , cmd_id ) ) ;
2022-04-10 12:32:01 +02:00
std : : lock_guard lock { vdec - > mutex } ;
if ( false ) // TODO: set to old state in case of error
{
vdec - > seq_state = old_state ;
}
else
{
vdec - > seq_state = sequence_state : : ready ;
}
2020-01-02 16:46:52 +01:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2022-09-07 10:19:56 +02:00
error_code cellVdecEndSeq ( ppu_thread & ppu , u32 handle )
2013-09-28 04:36:57 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2016-01-12 22:57:16 +01:00
cellVdec . warning ( " cellVdecEndSeq(handle=0x%x) " , handle ) ;
2014-02-27 19:25:32 +01:00
2018-10-11 00:17:19 +02:00
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2014-02-27 19:25:32 +01:00
2015-04-12 22:16:30 +02:00
if ( ! vdec )
2014-02-27 19:25:32 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
{
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state ! = sequence_state : : ready )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
vdec - > seq_state = sequence_state : : ending ;
}
2022-04-24 13:14:19 +02:00
const u64 seq_id = vdec - > seq_id ;
2022-04-23 18:25:00 +02:00
const u64 cmd_id = vdec - > next_cmd_id + + ;
2022-04-24 13:52:51 +02:00
cellVdec . trace ( " Adding end cmd (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , seq_id , cmd_id ) ;
2022-04-23 18:25:00 +02:00
2022-04-24 13:14:19 +02:00
vdec - > in_cmd . push ( vdec_cmd ( vdec_cmd_type : : end_sequence , seq_id , cmd_id ) ) ;
2020-01-02 16:46:52 +01:00
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2022-09-07 10:19:56 +02:00
error_code cellVdecDecodeAu ( ppu_thread & ppu , u32 handle , CellVdecDecodeMode mode , vm : : cptr < CellVdecAuInfo > auInfo )
2013-09-28 04:36:57 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2019-12-02 22:31:34 +01:00
cellVdec . trace ( " cellVdecDecodeAu(handle=0x%x, mode=%d, auInfo=*0x%x) " , handle , + mode , auInfo ) ;
2014-02-27 19:25:32 +01:00
2018-10-11 00:17:19 +02:00
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2014-02-27 19:25:32 +01:00
2022-04-13 18:02:01 +02:00
if ( ! vdec | | ! auInfo | | ! auInfo - > size | | ! auInfo - > startAddr )
2014-02-27 19:25:32 +01:00
{
2022-04-22 20:35:08 +02:00
return { CELL_VDEC_ERROR_ARG , " vdec=%d, auInfo=%d, size=%d, startAddr=0x%x " , ! ! vdec , ! ! auInfo , auInfo ? auInfo - > size . value ( ) : 0 , auInfo ? auInfo - > startAddr . value ( ) : 0 } ;
2014-02-27 19:25:32 +01:00
}
2022-04-10 12:32:01 +02:00
{
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state ! = sequence_state : : ready )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
}
2022-04-12 19:54:07 +02:00
if ( mode < 0 | | mode > ( CELL_VDEC_DEC_MODE_B_SKIP | CELL_VDEC_DEC_MODE_PB_SKIP ) )
2022-04-10 12:32:01 +02:00
{
2022-04-22 20:35:08 +02:00
return { CELL_VDEC_ERROR_ARG , " mode=%d " , + mode } ;
2022-04-10 12:32:01 +02:00
}
2022-04-12 19:54:07 +02:00
// TODO: what does the 3 stand for ?
2022-04-12 20:48:55 +02:00
if ( ( mode = = ( CELL_VDEC_DEC_MODE_B_SKIP | CELL_VDEC_DEC_MODE_PB_SKIP ) & & vdec - > type ! = 3 ) | |
2022-04-12 19:54:07 +02:00
( mode = = CELL_VDEC_DEC_MODE_PB_SKIP & & vdec - > type ! = CELL_VDEC_CODEC_TYPE_AVC ) )
{
2022-04-22 20:35:08 +02:00
return { CELL_VDEC_ERROR_ARG , " mode=%d, type=%d " , + mode , vdec - > type } ;
2022-04-12 19:54:07 +02:00
}
2022-04-10 12:32:01 +02:00
2018-10-11 00:17:19 +02:00
if ( ! vdec - > au_count . try_inc ( 4 ) )
2017-10-01 03:40:51 +02:00
{
return CELL_VDEC_ERROR_BUSY ;
}
2022-04-24 13:14:19 +02:00
const u64 seq_id = vdec - > seq_id ;
2022-04-23 18:25:00 +02:00
const u64 cmd_id = vdec - > next_cmd_id + + ;
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Adding decode cmd (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , seq_id , cmd_id ) ;
2022-04-23 18:25:00 +02:00
2014-02-27 19:25:32 +01:00
// TODO: check info
2022-04-24 13:14:19 +02:00
vdec - > in_cmd . push ( vdec_cmd ( vdec_cmd_type : : au_decode , seq_id , cmd_id , mode , * auInfo ) ) ;
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2022-09-07 10:19:56 +02:00
error_code cellVdecDecodeAuEx2 ( ppu_thread & ppu , u32 handle , CellVdecDecodeMode mode , vm : : cptr < CellVdecAuInfoEx2 > auInfo )
2019-04-05 20:14:01 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2022-04-12 20:48:55 +02:00
cellVdec . todo ( " cellVdecDecodeAuEx2(handle=0x%x, mode=%d, auInfo=*0x%x) " , handle , + mode , auInfo ) ;
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2022-04-13 18:02:01 +02:00
if ( ! vdec | | ! auInfo | | ! auInfo - > size | | ! auInfo - > startAddr )
2022-04-12 20:48:55 +02:00
{
2022-04-22 20:35:08 +02:00
return { CELL_VDEC_ERROR_ARG , " vdec=%d, auInfo=%d, size=%d, startAddr=0x%x " , ! ! vdec , ! ! auInfo , auInfo ? auInfo - > size . value ( ) : 0 , auInfo ? auInfo - > startAddr . value ( ) : 0 } ;
2022-04-12 20:48:55 +02:00
}
{
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state ! = sequence_state : : ready )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
}
if ( mode < 0 | | mode > ( CELL_VDEC_DEC_MODE_B_SKIP | CELL_VDEC_DEC_MODE_PB_SKIP ) )
{
2022-04-22 20:35:08 +02:00
return { CELL_VDEC_ERROR_ARG , " mode=%d " , + mode } ;
2022-04-12 20:48:55 +02:00
}
// TODO: what does the 3 stand for ?
if ( ( mode = = ( CELL_VDEC_DEC_MODE_B_SKIP | CELL_VDEC_DEC_MODE_PB_SKIP ) & & vdec - > type ! = 3 ) | |
( mode = = CELL_VDEC_DEC_MODE_PB_SKIP & & vdec - > type ! = CELL_VDEC_CODEC_TYPE_AVC ) )
{
2022-04-22 20:35:08 +02:00
return { CELL_VDEC_ERROR_ARG , " mode=%d, type=%d " , + mode , vdec - > type } ;
2022-04-12 20:48:55 +02:00
}
if ( ! vdec - > au_count . try_inc ( 4 ) )
{
return CELL_VDEC_ERROR_BUSY ;
}
CellVdecAuInfo au_info { } ;
au_info . startAddr = auInfo - > startAddr ;
au_info . size = auInfo - > size ;
au_info . pts = auInfo - > pts ;
au_info . dts = auInfo - > dts ;
au_info . userData = auInfo - > userData ;
au_info . codecSpecificData = auInfo - > codecSpecificData ;
2022-04-24 13:14:19 +02:00
const u64 seq_id = vdec - > seq_id ;
2022-04-23 18:25:00 +02:00
const u64 cmd_id = vdec - > next_cmd_id + + ;
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Adding decode cmd (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , seq_id , cmd_id ) ;
2022-04-23 18:25:00 +02:00
2022-04-12 20:48:55 +02:00
// TODO: check info
2022-04-24 13:14:19 +02:00
vdec - > in_cmd . push ( vdec_cmd ( vdec_cmd_type : : au_decode , seq_id , cmd_id , mode , au_info ) ) ;
2019-04-05 20:14:01 +02:00
return CELL_OK ;
}
2022-09-07 10:19:56 +02:00
error_code cellVdecGetPictureExt ( ppu_thread & ppu , u32 handle , vm : : cptr < CellVdecPicFormat2 > format , vm : : ptr < u8 > outBuff , u32 arg4 )
2013-09-28 04:36:57 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2022-04-13 21:41:53 +02:00
cellVdec . trace ( " cellVdecGetPictureExt(handle=0x%x, format=*0x%x, outBuff=*0x%x, arg4=*0x%x) " , handle , format , outBuff , arg4 ) ;
2014-03-01 09:38:50 +01:00
2018-10-11 00:17:19 +02:00
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2014-03-01 09:38:50 +01:00
2020-01-02 16:46:52 +01:00
if ( ! vdec | | ! format )
2014-03-01 09:38:50 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
{
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state = = sequence_state : : closed | | vdec - > seq_state > sequence_state : : ending )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
}
2020-01-02 16:46:52 +01:00
if ( format - > formatType > 4 | | ( format - > formatType < = CELL_VDEC_PICFMT_RGBA32_ILV & & format - > colorMatrixType > CELL_VDEC_COLOR_MATRIX_TYPE_BT709 ) )
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-13 21:41:53 +02:00
if ( arg4 & & arg4 ! = 8 & & arg4 ! = 0xc )
{
return CELL_VDEC_ERROR_ARG ;
}
if ( arg4 | | format - > unk0 | | format - > unk1 )
{
2022-04-23 15:09:08 +02:00
fmt : : throw_exception ( " cellVdecGetPictureExt: Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x) " , arg4 , format - > unk0 , format - > unk1 ) ;
2022-04-13 21:41:53 +02:00
}
2016-07-27 23:43:22 +02:00
vdec_frame frame ;
2018-10-11 00:17:19 +02:00
bool notify = false ;
2022-04-24 13:52:51 +02:00
u64 sequence_id { } ;
2014-03-01 09:38:50 +01:00
{
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( vdec - > mutex ) ;
2014-03-01 09:38:50 +01:00
2022-04-10 12:32:01 +02:00
if ( vdec - > out_queue . empty ( ) )
2016-07-27 23:43:22 +02:00
{
return CELL_VDEC_ERROR_EMPTY ;
}
2014-10-18 19:00:21 +02:00
2022-04-10 12:32:01 +02:00
frame = std : : move ( vdec - > out_queue . front ( ) ) ;
2022-04-24 13:52:51 +02:00
sequence_id = vdec - > seq_id ;
2014-03-03 00:02:42 +01:00
2022-04-10 12:32:01 +02:00
vdec - > out_queue . pop_front ( ) ;
if ( vdec - > out_queue . size ( ) + 1 = = vdec - > out_max )
2018-10-11 00:17:19 +02:00
notify = true ;
2016-07-27 23:43:22 +02:00
}
2018-10-11 00:17:19 +02:00
if ( notify )
2019-01-13 22:03:43 +01:00
{
auto vdec_ppu = idm : : get < named_thread < ppu_thread > > ( vdec - > ppu_tid ) ;
2019-08-12 06:56:58 +02:00
if ( vdec_ppu ) thread_ctrl : : notify ( * vdec_ppu ) ;
2019-01-13 22:03:43 +01:00
}
2017-11-24 19:56:51 +01:00
2022-04-24 13:52:51 +02:00
if ( sequence_id ! = frame . seq_id )
{
return { CELL_VDEC_ERROR_EMPTY , " sequence_id=%d, seq_id=%d " , sequence_id , frame . seq_id } ;
}
2015-02-11 12:39:51 +01:00
if ( outBuff )
{
2016-07-27 23:43:22 +02:00
const int w = frame - > width ;
const int h = frame - > height ;
2015-04-17 15:24:22 +02:00
2016-07-27 23:43:22 +02:00
AVPixelFormat out_f = AV_PIX_FMT_YUV420P ;
2015-04-17 15:24:22 +02:00
2015-04-21 21:35:11 +02:00
std : : unique_ptr < u8 [ ] > alpha_plane ;
2015-04-17 15:24:22 +02:00
2015-04-17 22:16:55 +02:00
switch ( const u32 type = format - > formatType )
2014-03-01 09:38:50 +01:00
{
2015-04-17 15:24:22 +02:00
case CELL_VDEC_PICFMT_ARGB32_ILV : out_f = AV_PIX_FMT_ARGB ; alpha_plane . reset ( new u8 [ w * h ] ) ; break ;
case CELL_VDEC_PICFMT_RGBA32_ILV : out_f = AV_PIX_FMT_RGBA ; alpha_plane . reset ( new u8 [ w * h ] ) ; break ;
case CELL_VDEC_PICFMT_UYVY422_ILV : out_f = AV_PIX_FMT_UYVY422 ; break ;
case CELL_VDEC_PICFMT_YUV420_PLANAR : out_f = AV_PIX_FMT_YUV420P ; break ;
2015-04-18 19:18:23 +02:00
default :
2014-03-01 09:38:50 +01:00
{
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " cellVdecGetPictureExt: Unknown formatType (handle=0x%x, seq_id=%d, cmd_id=%d, type=%d) " , handle , frame . seq_id , frame . cmd_id , type ) ;
2015-04-18 19:18:23 +02:00
}
2014-03-01 09:38:50 +01:00
}
2014-03-03 00:02:42 +01:00
2017-01-26 16:54:56 +01:00
// TODO: color matrix
2014-03-01 09:38:50 +01:00
2015-04-17 15:24:22 +02:00
if ( alpha_plane )
{
2016-07-27 23:43:22 +02:00
std : : memset ( alpha_plane . get ( ) , format - > alpha , w * h ) ;
2015-04-17 15:24:22 +02:00
}
2014-03-03 00:02:42 +01:00
2016-07-27 23:43:22 +02:00
AVPixelFormat in_f = AV_PIX_FMT_YUV420P ;
2014-03-01 09:38:50 +01:00
2016-07-27 23:43:22 +02:00
switch ( frame - > format )
2014-03-01 09:38:50 +01:00
{
2020-01-19 23:41:49 +01:00
case AV_PIX_FMT_YUVJ420P :
2022-04-24 13:14:19 +02:00
cellVdec . error ( " cellVdecGetPictureExt: experimental AVPixelFormat (handle=0x%x, seq_id=%d, cmd_id=%d, format=%d). This may cause suboptimal video quality. " , handle , frame . seq_id , frame . cmd_id , frame - > format ) ;
2018-09-06 13:28:12 +02:00
[[fallthrough]] ;
2020-01-19 23:41:49 +01:00
case AV_PIX_FMT_YUV420P :
in_f = alpha_plane ? AV_PIX_FMT_YUVA420P : static_cast < AVPixelFormat > ( frame - > format ) ;
break ;
2015-04-18 19:18:23 +02:00
default :
2022-04-23 15:09:08 +02:00
fmt : : throw_exception ( " cellVdecGetPictureExt: Unknown frame format (%d) " , frame - > format ) ;
2014-03-01 09:38:50 +01:00
}
2015-04-17 15:24:22 +02:00
2022-04-24 13:52:51 +02:00
cellVdec . trace ( " cellVdecGetPictureExt: handle=0x%x, seq_id=%d, cmd_id=%d, w=%d, h=%d, frameFormat=%d, formatType=%d, in_f=%d, out_f=%d, alpha_plane=%d, alpha=%d, colorMatrixType=%d " , handle , frame . seq_id , frame . cmd_id , w , h , frame - > format , format - > formatType , + in_f , + out_f , ! ! alpha_plane , format - > alpha , format - > colorMatrixType ) ;
2022-04-23 15:09:08 +02:00
2021-04-09 21:12:47 +02:00
vdec - > sws = sws_getCachedContext ( vdec - > sws , w , h , in_f , w , h , out_f , SWS_POINT , nullptr , nullptr , nullptr ) ;
2014-03-03 00:02:42 +01:00
2015-04-17 15:24:22 +02:00
u8 * in_data [ 4 ] = { frame - > data [ 0 ] , frame - > data [ 1 ] , frame - > data [ 2 ] , alpha_plane . get ( ) } ;
int in_line [ 4 ] = { frame - > linesize [ 0 ] , frame - > linesize [ 1 ] , frame - > linesize [ 2 ] , w * 1 } ;
u8 * out_data [ 4 ] = { outBuff . get_ptr ( ) } ;
2023-03-05 02:53:22 +01:00
int out_line [ 4 ] = { w * 4 } ; // RGBA32 or ARGB32
// TODO:
// It's possible that we need to align the pitch to 128 here.
// PS HOME seems to rely on this somehow in certain cases.
2014-03-01 09:38:50 +01:00
2015-04-17 15:24:22 +02:00
if ( ! alpha_plane )
2014-03-01 09:38:50 +01:00
{
2022-04-13 00:03:15 +02:00
// YUV420P or UYVY422
2015-04-17 15:24:22 +02:00
out_data [ 1 ] = out_data [ 0 ] + w * h ;
out_data [ 2 ] = out_data [ 0 ] + w * h * 5 / 4 ;
2022-04-13 00:03:15 +02:00
if ( const int ret = av_image_fill_linesizes ( out_line , out_f , w ) ; ret < 0 )
{
2022-04-24 13:14:19 +02:00
fmt : : throw_exception ( " cellVdecGetPictureExt: av_image_fill_linesizes failed (handle=0x%x, seq_id=%d, cmd_id=%d, ret=0x%x): %s " , handle , frame . seq_id , frame . cmd_id , ret , utils : : av_error_to_string ( ret ) ) ;
2022-04-13 00:03:15 +02:00
}
2014-03-01 09:38:50 +01:00
}
2015-04-17 15:24:22 +02:00
2017-11-24 19:56:51 +01:00
sws_scale ( vdec - > sws , in_data , in_line , 0 , h , out_data , out_line ) ;
2014-03-01 09:38:50 +01:00
}
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2022-09-07 10:19:56 +02:00
error_code cellVdecGetPicture ( ppu_thread & ppu , u32 handle , vm : : cptr < CellVdecPicFormat > format , vm : : ptr < u8 > outBuff )
2013-09-28 04:36:57 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2022-04-13 21:41:53 +02:00
cellVdec . trace ( " cellVdecGetPicture(handle=0x%x, format=*0x%x, outBuff=*0x%x) " , handle , format , outBuff ) ;
2022-04-10 12:32:01 +02:00
2022-04-13 21:41:53 +02:00
if ( ! format )
2022-04-10 12:32:01 +02:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-13 21:41:53 +02:00
vm : : var < CellVdecPicFormat2 > format2 ;
format2 - > formatType = format - > formatType ;
format2 - > colorMatrixType = format - > colorMatrixType ;
format2 - > alpha = format - > alpha ;
format2 - > unk0 = 0 ;
format2 - > unk1 = 0 ;
2015-04-17 15:24:22 +02:00
2022-09-07 10:19:56 +02:00
return cellVdecGetPictureExt ( ppu , handle , format2 , outBuff , 0 ) ;
2015-04-17 15:24:22 +02:00
}
2022-09-07 10:19:56 +02:00
error_code cellVdecGetPicItem ( ppu_thread & ppu , u32 handle , vm : : pptr < CellVdecPicItem > picItem )
2013-09-28 04:36:57 +02:00
{
2022-09-07 10:19:56 +02:00
ppu . state + = cpu_flag : : wait ;
2016-01-12 22:57:16 +01:00
cellVdec . trace ( " cellVdecGetPicItem(handle=0x%x, picItem=**0x%x) " , handle , picItem ) ;
2015-04-12 22:16:30 +02:00
2018-10-11 00:17:19 +02:00
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2014-03-01 09:38:50 +01:00
2020-01-02 16:46:52 +01:00
if ( ! vdec | | ! picItem )
2014-03-01 09:38:50 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-24 13:52:51 +02:00
u64 sequence_id { } ;
2022-04-10 12:32:01 +02:00
{
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state = = sequence_state : : closed | | vdec - > seq_state > sequence_state : : ending )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
2022-04-24 13:52:51 +02:00
sequence_id = vdec - > seq_id ;
2022-04-10 12:32:01 +02:00
}
2020-01-02 16:46:52 +01:00
2020-02-03 16:31:29 +01:00
struct all_info_t
{
CellVdecPicItem picItem ;
std : : aligned_union_t < 0 , CellVdecAvcInfo , CellVdecDivxInfo , CellVdecMpeg2Info > picInfo ;
} ;
2016-07-27 23:43:22 +02:00
AVFrame * frame { } ;
2022-04-24 13:14:19 +02:00
u64 seq_id { } ;
2022-04-23 18:25:00 +02:00
u64 cmd_id { } ;
2016-07-27 23:43:22 +02:00
u64 pts ;
u64 dts ;
u64 usrd ;
2021-02-17 20:58:10 +01:00
u32 frc = 0 ;
2022-04-12 01:31:57 +02:00
CellVdecPicAttr attr = CELL_VDEC_PICITEM_ATTR_NORMAL ;
2020-02-03 16:31:29 +01:00
vm : : ptr < CellVdecPicItem > info ;
2014-03-01 09:38:50 +01:00
{
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( vdec - > mutex ) ;
2016-07-27 23:43:22 +02:00
2022-04-10 12:32:01 +02:00
for ( auto & picture : vdec - > out_queue )
2016-07-27 23:43:22 +02:00
{
2022-04-12 01:31:57 +02:00
if ( ! picture . pic_item_received )
2019-03-13 08:14:27 +01:00
{
2022-04-12 01:31:57 +02:00
picture . pic_item_received = true ;
2019-03-13 08:14:27 +01:00
frame = picture . avf . get ( ) ;
2022-04-24 13:14:19 +02:00
seq_id = picture . seq_id ;
2022-04-23 18:25:00 +02:00
cmd_id = picture . cmd_id ;
2019-03-13 08:14:27 +01:00
pts = picture . pts ;
dts = picture . dts ;
usrd = picture . userdata ;
frc = picture . frc ;
2022-04-12 01:31:57 +02:00
attr = picture . attr ;
2020-02-03 16:31:29 +01:00
info . set ( vdec - > mem_addr + vdec - > mem_bias ) ;
constexpr u64 size_needed = sizeof ( all_info_t ) ;
if ( vdec - > mem_bias + size_needed > = vdec - > mem_size / size_needed * size_needed )
{
vdec - > mem_bias = 0 ;
break ;
}
vdec - > mem_bias + = size_needed ;
2019-03-13 08:14:27 +01:00
break ;
}
2016-07-27 23:43:22 +02:00
}
2019-03-13 08:14:27 +01:00
}
2014-03-01 09:38:50 +01:00
2022-04-24 13:52:51 +02:00
if ( ! frame | | seq_id ! = sequence_id )
2019-03-13 08:14:27 +01:00
{
// If frame is empty info was not found
2022-04-24 13:52:51 +02:00
return { CELL_VDEC_ERROR_EMPTY , " frame=%d, sequence_id=%d, seq_id=%d " , ! ! frame , sequence_id , seq_id } ;
2016-07-27 23:43:22 +02:00
}
2014-03-03 00:02:42 +01:00
2014-03-01 09:38:50 +01:00
info - > codecType = vdec - > type ;
info - > startAddr = 0x00000123 ; // invalid value (no address for picture)
2019-12-16 20:56:14 +01:00
const int buffer_size = av_image_get_buffer_size ( vdec - > ctx - > pix_fmt , vdec - > ctx - > width , vdec - > ctx - > height , 1 ) ;
2020-12-09 08:47:45 +01:00
ensure ( buffer_size > = 0 ) ;
2020-12-18 15:43:34 +01:00
info - > size = utils : : align < u32 > ( buffer_size , 128 ) ;
2014-03-01 09:38:50 +01:00
info - > auNum = 1 ;
2019-12-02 22:31:34 +01:00
info - > auPts [ 0 ] . lower = static_cast < u32 > ( pts ) ;
info - > auPts [ 0 ] . upper = static_cast < u32 > ( pts > > 32 ) ;
2022-04-11 23:52:23 +02:00
info - > auPts [ 1 ] . lower = CELL_CODEC_PTS_INVALID ;
info - > auPts [ 1 ] . upper = CELL_CODEC_PTS_INVALID ;
2019-12-02 22:31:34 +01:00
info - > auDts [ 0 ] . lower = static_cast < u32 > ( dts ) ;
info - > auDts [ 0 ] . upper = static_cast < u32 > ( dts > > 32 ) ;
2022-04-11 23:52:23 +02:00
info - > auDts [ 1 ] . lower = CELL_CODEC_DTS_INVALID ;
info - > auDts [ 1 ] . upper = CELL_CODEC_DTS_INVALID ;
2016-07-27 23:43:22 +02:00
info - > auUserData [ 0 ] = usrd ;
2014-03-01 09:38:50 +01:00
info - > auUserData [ 1 ] = 0 ;
info - > status = CELL_OK ;
2022-04-12 01:31:57 +02:00
info - > attr = attr ;
2020-02-03 16:31:29 +01:00
const vm : : addr_t picinfo_addr { info . addr ( ) + : : offset32 ( & all_info_t : : picInfo ) } ;
info - > picInfo_addr = picinfo_addr ;
2014-03-01 09:38:50 +01:00
2014-12-09 17:13:03 +01:00
if ( vdec - > type = = CELL_VDEC_CODEC_TYPE_AVC )
{
2020-02-03 16:31:29 +01:00
const vm : : ptr < CellVdecAvcInfo > avc = picinfo_addr ;
2014-12-09 17:13:03 +01:00
2016-07-27 23:43:22 +02:00
avc - > horizontalSize = frame - > width ;
avc - > verticalSize = frame - > height ;
2016-07-22 14:54:35 +02:00
2016-08-03 22:51:05 +02:00
switch ( s32 pct = frame - > pict_type )
2014-03-31 12:04:34 +02:00
{
2014-12-09 17:13:03 +01:00
case AV_PICTURE_TYPE_I : avc - > pictureType [ 0 ] = CELL_VDEC_AVC_PCT_I ; break ;
case AV_PICTURE_TYPE_P : avc - > pictureType [ 0 ] = CELL_VDEC_AVC_PCT_P ; break ;
case AV_PICTURE_TYPE_B : avc - > pictureType [ 0 ] = CELL_VDEC_AVC_PCT_B ; break ;
2022-04-23 15:09:08 +02:00
default :
{
avc - > pictureType [ 0 ] = CELL_VDEC_AVC_PCT_UNKNOWN ;
2022-04-24 13:14:19 +02:00
cellVdec . error ( " cellVdecGetPicItem(AVC): unknown pict_type value (handle=0x%x, seq_id=%d, cmd_id=%d, pct=0x%x) " , handle , seq_id , cmd_id , pct ) ;
2022-04-23 15:09:08 +02:00
break ;
}
2014-03-31 12:04:34 +02:00
}
2016-07-22 14:54:35 +02:00
2014-12-09 17:13:03 +01:00
avc - > pictureType [ 1 ] = CELL_VDEC_AVC_PCT_UNKNOWN ; // ???
avc - > idrPictureFlag = false ; // ???
avc - > aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED ; // ???
avc - > sar_height = 0 ;
avc - > sar_width = 0 ;
avc - > pic_struct = CELL_VDEC_AVC_PSTR_FRAME ; // ???
avc - > picOrderCount [ 0 ] = 0 ; // ???
avc - > picOrderCount [ 1 ] = 0 ;
avc - > vui_parameters_present_flag = true ; // ???
avc - > frame_mbs_only_flag = true ; // ??? progressive
avc - > video_signal_type_present_flag = true ; // ???
avc - > video_format = CELL_VDEC_AVC_VF_COMPONENT ; // ???
avc - > video_full_range_flag = false ; // ???
avc - > colour_description_present_flag = true ;
avc - > colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5 ; // ???
avc - > transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5 ;
avc - > matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5 ; // important
avc - > timing_info_present_flag = true ;
2017-11-24 19:56:51 +01:00
2016-07-27 23:43:22 +02:00
switch ( frc )
2014-03-31 12:04:34 +02:00
{
2014-12-09 17:13:03 +01:00
case CELL_VDEC_FRC_24000DIV1001 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001 ; break ;
case CELL_VDEC_FRC_24 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_24 ; break ;
case CELL_VDEC_FRC_25 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_25 ; break ;
case CELL_VDEC_FRC_30000DIV1001 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001 ; break ;
case CELL_VDEC_FRC_30 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_30 ; break ;
case CELL_VDEC_FRC_50 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_50 ; break ;
case CELL_VDEC_FRC_60000DIV1001 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001 ; break ;
case CELL_VDEC_FRC_60 : avc - > frameRateCode = CELL_VDEC_AVC_FRC_60 ; break ;
2022-04-24 13:14:19 +02:00
default : cellVdec . error ( " cellVdecGetPicItem(AVC): unknown frc value (handle=0x%x, seq_id=%d, cmd_id=%d, frc=0x%x) " , handle , seq_id , cmd_id , frc ) ;
2014-03-31 12:04:34 +02:00
}
2014-12-09 17:13:03 +01:00
avc - > fixed_frame_rate_flag = true ;
avc - > low_delay_hrd_flag = true ; // ???
avc - > entropy_coding_mode_flag = true ; // ???
avc - > nalUnitPresentFlags = 0 ; // ???
avc - > ccDataLength [ 0 ] = 0 ;
avc - > ccDataLength [ 1 ] = 0 ;
avc - > reserved [ 0 ] = 0 ;
avc - > reserved [ 1 ] = 0 ;
}
else if ( vdec - > type = = CELL_VDEC_CODEC_TYPE_DIVX )
{
2020-02-03 16:31:29 +01:00
const vm : : ptr < CellVdecDivxInfo > dvx = picinfo_addr ;
2014-12-09 17:13:03 +01:00
2016-08-03 22:51:05 +02:00
switch ( s32 pct = frame - > pict_type )
2014-03-31 12:04:34 +02:00
{
2014-12-09 17:13:03 +01:00
case AV_PICTURE_TYPE_I : dvx - > pictureType = CELL_VDEC_DIVX_VCT_I ; break ;
case AV_PICTURE_TYPE_P : dvx - > pictureType = CELL_VDEC_DIVX_VCT_P ; break ;
case AV_PICTURE_TYPE_B : dvx - > pictureType = CELL_VDEC_DIVX_VCT_B ; break ;
2022-04-24 13:14:19 +02:00
default : cellVdec . error ( " cellVdecGetPicItem(DivX): unknown pict_type value (handle=0x%x, seq_id=%d, cmd_id=%d, pct=0x%x) " , handle , seq_id , cmd_id , pct ) ;
2014-12-09 17:13:03 +01:00
}
2016-07-22 14:54:35 +02:00
2016-07-27 23:43:22 +02:00
dvx - > horizontalSize = frame - > width ;
dvx - > verticalSize = frame - > height ;
2014-12-09 17:13:03 +01:00
dvx - > pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1 ; // ???
dvx - > parHeight = 0 ;
dvx - > parWidth = 0 ;
dvx - > colourDescription = false ; // ???
dvx - > colourPrimaries = CELL_VDEC_DIVX_CP_ITU_R_BT_709 ; // ???
dvx - > transferCharacteristics = CELL_VDEC_DIVX_TC_ITU_R_BT_709 ; // ???
dvx - > matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709 ; // ???
dvx - > pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME ; // ???
2016-07-22 14:54:35 +02:00
2016-07-27 23:43:22 +02:00
switch ( frc )
2014-12-09 17:13:03 +01:00
{
case CELL_VDEC_FRC_24000DIV1001 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_24000DIV1001 ; break ;
case CELL_VDEC_FRC_24 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_24 ; break ;
case CELL_VDEC_FRC_25 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_25 ; break ;
case CELL_VDEC_FRC_30000DIV1001 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_30000DIV1001 ; break ;
case CELL_VDEC_FRC_30 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_30 ; break ;
case CELL_VDEC_FRC_50 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_50 ; break ;
case CELL_VDEC_FRC_60000DIV1001 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_60000DIV1001 ; break ;
case CELL_VDEC_FRC_60 : dvx - > frameRateCode = CELL_VDEC_DIVX_FRC_60 ; break ;
2022-04-24 13:14:19 +02:00
default : cellVdec . error ( " cellVdecGetPicItem(DivX): unknown frc value (handle=0x%x, seq_id=%d, cmd_id=%d, frc=0x%x) " , handle , seq_id , cmd_id , frc ) ;
2014-03-31 12:04:34 +02:00
}
}
2014-12-09 17:13:03 +01:00
else if ( vdec - > type = = CELL_VDEC_CODEC_TYPE_MPEG2 )
2014-03-31 12:04:34 +02:00
{
2020-02-03 16:31:29 +01:00
const vm : : ptr < CellVdecMpeg2Info > mp2 = picinfo_addr ;
2016-07-22 14:54:35 +02:00
std : : memset ( mp2 . get_ptr ( ) , 0 , sizeof ( CellVdecMpeg2Info ) ) ;
2016-07-27 23:43:22 +02:00
mp2 - > horizontal_size = frame - > width ;
mp2 - > vertical_size = frame - > height ;
2016-07-22 14:54:35 +02:00
mp2 - > aspect_ratio_information = CELL_VDEC_MPEG2_ARI_SAR_1_1 ; // ???
2017-11-24 19:56:51 +01:00
2016-07-27 23:43:22 +02:00
switch ( frc )
2016-07-22 14:54:35 +02:00
{
case CELL_VDEC_FRC_24000DIV1001 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_24000DIV1001 ; break ;
case CELL_VDEC_FRC_24 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_24 ; break ;
case CELL_VDEC_FRC_25 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_25 ; break ;
case CELL_VDEC_FRC_30000DIV1001 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_30000DIV1001 ; break ;
case CELL_VDEC_FRC_30 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_30 ; break ;
case CELL_VDEC_FRC_50 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_50 ; break ;
case CELL_VDEC_FRC_60000DIV1001 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_60000DIV1001 ; break ;
case CELL_VDEC_FRC_60 : mp2 - > frame_rate_code = CELL_VDEC_MPEG2_FRC_60 ; break ;
2022-04-24 13:14:19 +02:00
default : cellVdec . error ( " cellVdecGetPicItem(MPEG2): unknown frc value (handle=0x%x, seq_id=%d, cmd_id=%d, frc=0x%x) " , handle , seq_id , cmd_id , frc ) ;
2016-07-22 14:54:35 +02:00
}
mp2 - > progressive_sequence = true ; // ???
mp2 - > low_delay = true ; // ???
mp2 - > video_format = CELL_VDEC_MPEG2_VF_UNSPECIFIED ; // ???
mp2 - > colour_description = false ; // ???
2016-08-03 22:51:05 +02:00
switch ( s32 pct = frame - > pict_type )
2016-07-22 14:54:35 +02:00
{
case AV_PICTURE_TYPE_I : mp2 - > picture_coding_type [ 0 ] = CELL_VDEC_MPEG2_PCT_I ; break ;
case AV_PICTURE_TYPE_P : mp2 - > picture_coding_type [ 0 ] = CELL_VDEC_MPEG2_PCT_P ; break ;
case AV_PICTURE_TYPE_B : mp2 - > picture_coding_type [ 0 ] = CELL_VDEC_MPEG2_PCT_B ; break ;
2022-04-24 13:14:19 +02:00
default : cellVdec . error ( " cellVdecGetPicItem(MPEG2): unknown pict_type value (handle=0x%x, seq_id=%d, cmd_id=%d, pct=0x%x) " , handle , seq_id , cmd_id , pct ) ;
2016-07-22 14:54:35 +02:00
}
mp2 - > picture_coding_type [ 1 ] = CELL_VDEC_MPEG2_PCT_FORBIDDEN ; // ???
mp2 - > picture_structure [ 0 ] = CELL_VDEC_MPEG2_PSTR_FRAME ;
mp2 - > picture_structure [ 1 ] = CELL_VDEC_MPEG2_PSTR_FRAME ;
2014-12-09 17:13:03 +01:00
2016-07-22 14:54:35 +02:00
// ...
2014-03-31 12:04:34 +02:00
}
2014-03-01 09:38:50 +01:00
2015-04-12 22:16:30 +02:00
* picItem = info ;
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2020-01-02 16:46:52 +01:00
error_code cellVdecSetFrameRate ( u32 handle , CellVdecFrameRate frameRateCode )
2013-09-28 04:36:57 +02:00
{
2020-01-02 16:46:52 +01:00
cellVdec . trace ( " cellVdecSetFrameRate(handle=0x%x, frameRateCode=0x%x) " , handle , + frameRateCode ) ;
2014-02-27 19:25:32 +01:00
2018-10-11 00:17:19 +02:00
const auto vdec = idm : : get < vdec_context > ( handle ) ;
2014-02-27 19:25:32 +01:00
2020-01-15 22:42:44 +01:00
// 0x80 seems like a common prefix
2020-01-21 14:24:37 +01:00
if ( ! vdec | | ( frameRateCode & 0xf8 ) ! = 0x80 )
2014-02-27 19:25:32 +01:00
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
std : : lock_guard lock { vdec - > mutex } ;
2020-01-02 16:46:52 +01:00
2022-04-10 12:32:01 +02:00
if ( vdec - > seq_state = = sequence_state : : closed | | vdec - > seq_state > = sequence_state : : invalid )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
2022-04-24 13:14:19 +02:00
const u64 seq_id = vdec - > seq_id ;
2022-04-23 18:25:00 +02:00
const u64 cmd_id = vdec - > next_cmd_id + + ;
2022-04-24 13:14:19 +02:00
cellVdec . trace ( " Adding framerate cmd (handle=0x%x, seq_id=%d, cmd_id=%d) " , handle , seq_id , cmd_id ) ;
2022-04-23 18:25:00 +02:00
2022-04-24 13:14:19 +02:00
vdec - > in_cmd . push ( vdec_cmd ( vdec_cmd_type : : framerate , seq_id , cmd_id , frameRateCode & 0x87 ) ) ;
2013-09-28 04:36:57 +02:00
return CELL_OK ;
}
2019-09-08 17:13:58 +02:00
error_code cellVdecOpenExt ( )
2017-02-12 00:54:37 +01:00
{
UNIMPLEMENTED_FUNC ( cellVdec ) ;
return CELL_OK ;
}
2019-09-08 17:13:58 +02:00
error_code cellVdecStartSeqExt ( )
2017-02-12 00:54:37 +01:00
{
UNIMPLEMENTED_FUNC ( cellVdec ) ;
return CELL_OK ;
}
2022-04-10 12:32:01 +02:00
error_code cellVdecGetInputStatus ( )
{
UNIMPLEMENTED_FUNC ( cellVdec ) ;
return CELL_OK ;
}
2019-09-08 17:13:58 +02:00
error_code cellVdecGetPicItemEx ( )
2019-04-05 20:14:01 +02:00
{
UNIMPLEMENTED_FUNC ( cellVdec ) ;
return CELL_OK ;
}
2019-09-08 17:13:58 +02:00
error_code cellVdecGetPicItemExt ( )
2017-02-12 00:54:37 +01:00
{
UNIMPLEMENTED_FUNC ( cellVdec ) ;
return CELL_OK ;
}
2019-09-08 17:13:58 +02:00
error_code cellVdecSetFrameRateExt ( )
2017-02-12 00:54:37 +01:00
{
UNIMPLEMENTED_FUNC ( cellVdec ) ;
return CELL_OK ;
}
2020-01-02 16:46:52 +01:00
error_code cellVdecSetPts ( u32 handle , vm : : ptr < void > unk )
2017-02-12 00:54:37 +01:00
{
2020-01-02 16:46:52 +01:00
cellVdec . error ( " cellVdecSetPts(handle=0x%x, unk=*0x%x) " , handle , unk ) ;
const auto vdec = idm : : get < vdec_context > ( handle ) ;
if ( ! vdec | | ! unk )
{
return CELL_VDEC_ERROR_ARG ;
}
2022-04-10 12:32:01 +02:00
std : : lock_guard lock { vdec - > mutex } ;
if ( vdec - > seq_state = = sequence_state : : closed | | vdec - > seq_state > = sequence_state : : invalid )
{
return { CELL_VDEC_ERROR_SEQ , vdec - > seq_state . load ( ) } ;
}
2020-01-02 16:46:52 +01:00
2017-02-12 00:54:37 +01:00
return CELL_OK ;
}
2016-03-21 20:43:03 +01:00
DECLARE ( ppu_module_manager : : cellVdec ) ( " libvdec " , [ ] ( )
2013-09-28 04:36:57 +02:00
{
2022-01-23 13:23:54 +01:00
# if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all ( ) ;
# endif
2017-02-12 19:35:55 +01:00
static ppu_static_module libavcdec ( " libavcdec " ) ;
static ppu_static_module libdivx311dec ( " libdivx311dec " ) ;
static ppu_static_module libdivxdec ( " libdivxdec " ) ;
static ppu_static_module libmvcdec ( " libmvcdec " ) ;
static ppu_static_module libsjvtd ( " libsjvtd " ) ;
static ppu_static_module libsmvd2 ( " libsmvd2 " ) ;
static ppu_static_module libsmvd4 ( " libsmvd4 " ) ;
static ppu_static_module libsvc1d ( " libsvc1d " ) ;
2016-03-21 20:43:03 +01:00
REG_VAR ( libvdec , _cell_vdec_prx_ver ) ; // 0x085a7ecb
REG_FUNC ( libvdec , cellVdecQueryAttr ) ;
REG_FUNC ( libvdec , cellVdecQueryAttrEx ) ;
REG_FUNC ( libvdec , cellVdecOpen ) ;
REG_FUNC ( libvdec , cellVdecOpenEx ) ;
2017-02-12 00:54:37 +01:00
REG_FUNC ( libvdec , cellVdecOpenExt ) ; // 0xef4d8ad7
2016-03-21 20:43:03 +01:00
REG_FUNC ( libvdec , cellVdecClose ) ;
REG_FUNC ( libvdec , cellVdecStartSeq ) ;
2017-02-12 00:54:37 +01:00
REG_FUNC ( libvdec , cellVdecStartSeqExt ) ; // 0xebb8e70a
2016-03-21 20:43:03 +01:00
REG_FUNC ( libvdec , cellVdecEndSeq ) ;
REG_FUNC ( libvdec , cellVdecDecodeAu ) ;
2019-04-05 20:14:01 +02:00
REG_FUNC ( libvdec , cellVdecDecodeAuEx2 ) ;
2022-04-10 12:32:01 +02:00
REG_FUNC ( libvdec , cellVdecGetInputStatus ) ;
2016-03-21 20:43:03 +01:00
REG_FUNC ( libvdec , cellVdecGetPicture ) ;
REG_FUNC ( libvdec , cellVdecGetPictureExt ) ; // 0xa21aa896
REG_FUNC ( libvdec , cellVdecGetPicItem ) ;
2019-04-05 20:14:01 +02:00
REG_FUNC ( libvdec , cellVdecGetPicItemEx ) ;
2017-02-12 00:54:37 +01:00
REG_FUNC ( libvdec , cellVdecGetPicItemExt ) ; // 0x2cbd9806
2016-03-21 20:43:03 +01:00
REG_FUNC ( libvdec , cellVdecSetFrameRate ) ;
2017-02-12 00:54:37 +01:00
REG_FUNC ( libvdec , cellVdecSetFrameRateExt ) ; // 0xcffc42a5
REG_FUNC ( libvdec , cellVdecSetPts ) ; // 0x3ce2e4f8
2018-10-11 00:17:19 +02:00
2021-09-06 09:33:44 +02:00
REG_HIDDEN_FUNC ( vdecEntry ) ;
2015-02-18 17:22:06 +01:00
} ) ;