2014-01-19 11:52:30 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2014-02-24 01:00:42 +01:00
|
|
|
#include "Utilities/SQueue.h"
|
|
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
// align size or address to 128
|
|
|
|
|
#define a128(x) ((x + 127) & (~127))
|
|
|
|
|
|
2014-01-19 11:52:30 +01:00
|
|
|
// Error Codes
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_ERROR_ARG = 0x80610201,
|
|
|
|
|
CELL_DMUX_ERROR_SEQ = 0x80610202,
|
|
|
|
|
CELL_DMUX_ERROR_BUSY = 0x80610203,
|
|
|
|
|
CELL_DMUX_ERROR_EMPTY = 0x80610204,
|
|
|
|
|
CELL_DMUX_ERROR_FATAL = 0x80610205,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxStreamType
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_STREAM_TYPE_UNDEF = 0,
|
|
|
|
|
CELL_DMUX_STREAM_TYPE_PAMF = 1,
|
|
|
|
|
CELL_DMUX_STREAM_TYPE_TERMINATOR = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxMsgType
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_MSG_TYPE_DEMUX_DONE = 0,
|
|
|
|
|
CELL_DMUX_MSG_TYPE_FATAL_ERR = 1,
|
|
|
|
|
CELL_DMUX_MSG_TYPE_PROG_END_CODE = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxEsMsgType
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_ES_MSG_TYPE_AU_FOUND = 0,
|
|
|
|
|
CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE = 1,
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-24 01:00:42 +01:00
|
|
|
enum CellDmuxPamfM2vLevel
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_M2V_MP_LL = 0,
|
|
|
|
|
CELL_DMUX_PAMF_M2V_MP_ML,
|
|
|
|
|
CELL_DMUX_PAMF_M2V_MP_H14,
|
|
|
|
|
CELL_DMUX_PAMF_M2V_MP_HL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxPamfAvcLevel
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_AVC_LEVEL_2P1 = 21,
|
|
|
|
|
CELL_DMUX_PAMF_AVC_LEVEL_3P0 = 30,
|
|
|
|
|
CELL_DMUX_PAMF_AVC_LEVEL_3P1 = 31,
|
|
|
|
|
CELL_DMUX_PAMF_AVC_LEVEL_3P2 = 32,
|
|
|
|
|
CELL_DMUX_PAMF_AVC_LEVEL_4P1 = 41,
|
|
|
|
|
CELL_DMUX_PAMF_AVC_LEVEL_4P2 = 42,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfAuSpecificInfoM2v
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfAuSpecificInfoAvc
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfAuSpecificInfoLpcm
|
|
|
|
|
{
|
|
|
|
|
u8 channelAssignmentInfo;
|
|
|
|
|
u8 samplingFreqInfo;
|
|
|
|
|
u8 bitsPerSample;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfAuSpecificInfoAc3
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfAuSpecificInfoAtrac3plus
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfAuSpecificInfoUserData
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfEsSpecificInfoM2v
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> profileLevel;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfEsSpecificInfoAvc
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> level;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfEsSpecificInfoLpcm
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> samplingFreq;
|
|
|
|
|
be_t<u32> numOfChannels;
|
|
|
|
|
be_t<u32> bitsPerSample;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfEsSpecificInfoAc3
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfEsSpecificInfoAtrac3plus
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxPamfEsSpecificInfoUserData
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> reserved1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxPamfSamplingFrequency
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_FS_48K = 48000,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxPamfBitsPerSample
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_BITS_PER_SAMPLE_16 = 16,
|
|
|
|
|
CELL_DMUX_PAMF_BITS_PER_SAMPLE_24 = 24,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxPamfLpcmChannelAssignmentInfo
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_CH_M1 = 1,
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_CH_LR = 3,
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_CH_LRCLSRSLFE = 9,
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_CH_LRCLSCS1CS2RSLFE = 11,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxPamfLpcmFs
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_FS_48K = 1,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum CellDmuxPamfLpcmBitsPerSamples
|
|
|
|
|
{
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_16 = 1,
|
|
|
|
|
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_24 = 3,
|
|
|
|
|
};
|
|
|
|
|
|
2014-01-19 11:52:30 +01:00
|
|
|
struct CellDmuxMsg
|
|
|
|
|
{
|
|
|
|
|
be_t<CellDmuxMsgType> msgType; //CellDmuxMsgType enum
|
|
|
|
|
be_t<u64> supplementalInfo;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxEsMsg
|
|
|
|
|
{
|
|
|
|
|
be_t<CellDmuxEsMsgType> msgType; //CellDmuxEsMsgType enum
|
|
|
|
|
be_t<u64> supplementalInfo;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxType
|
|
|
|
|
{
|
2014-02-24 01:00:42 +01:00
|
|
|
be_t<CellDmuxStreamType> streamType;
|
2014-01-19 11:52:30 +01:00
|
|
|
be_t<u32> reserved[2]; //0
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-24 01:00:42 +01:00
|
|
|
struct CellDmuxPamfSpecificInfo
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> thisSize;
|
|
|
|
|
bool programEndCodeCb;
|
|
|
|
|
};
|
|
|
|
|
|
2014-01-19 11:52:30 +01:00
|
|
|
struct CellDmuxType2
|
|
|
|
|
{
|
2014-02-24 01:00:42 +01:00
|
|
|
be_t<CellDmuxStreamType> streamType;
|
2014-01-19 11:52:30 +01:00
|
|
|
be_t<u32> streamSpecificInfo_addr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxResource
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> memAddr;
|
|
|
|
|
be_t<u32> memSize;
|
|
|
|
|
be_t<u32> ppuThreadPriority;
|
|
|
|
|
be_t<u32> ppuThreadStackSize;
|
|
|
|
|
be_t<u32> spuThreadPriority;
|
|
|
|
|
be_t<u32> numOfSpus;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxResourceEx
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> memAddr;
|
|
|
|
|
be_t<u32> memSize;
|
|
|
|
|
be_t<u32> ppuThreadPriority;
|
|
|
|
|
be_t<u32> ppuThreadStackSize;
|
|
|
|
|
be_t<u32> spurs_addr;
|
|
|
|
|
u8 priority[8];
|
|
|
|
|
be_t<u32> maxContention;
|
|
|
|
|
};
|
|
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
/*
|
2014-01-19 11:52:30 +01:00
|
|
|
struct CellDmuxResource2Ex
|
|
|
|
|
{
|
|
|
|
|
bool isResourceEx; //true
|
|
|
|
|
CellDmuxResourceEx resourceEx;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxResource2NoEx
|
|
|
|
|
{
|
|
|
|
|
bool isResourceEx; //false
|
|
|
|
|
CellDmuxResource resource;
|
|
|
|
|
};
|
2014-01-19 22:19:37 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct CellDmuxResource2
|
|
|
|
|
{
|
|
|
|
|
bool isResourceEx;
|
|
|
|
|
be_t<u32> memAddr;
|
|
|
|
|
be_t<u32> memSize;
|
|
|
|
|
be_t<u32> ppuThreadPriority;
|
|
|
|
|
be_t<u32> ppuThreadStackSize;
|
2014-02-24 00:40:03 +01:00
|
|
|
be_t<u32> shit[4];
|
2014-01-19 22:19:37 +01:00
|
|
|
};
|
2014-01-19 11:52:30 +01:00
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
typedef mem_func_ptr_t<void (*)(u32 demuxerHandle, mem_ptr_t<CellDmuxMsg> demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg;
|
2014-02-24 01:00:42 +01:00
|
|
|
|
2014-01-19 11:52:30 +01:00
|
|
|
struct CellDmuxCb
|
|
|
|
|
{
|
|
|
|
|
// CellDmuxCbMsg callback
|
2014-02-24 01:00:42 +01:00
|
|
|
be_t<u32> cbMsgFunc;
|
2014-01-19 11:52:30 +01:00
|
|
|
be_t<u32> cbArg_addr;
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
typedef mem_func_ptr_t<void (*)(u32 demuxerHandle, u32 esHandle, mem_ptr_t<CellDmuxEsMsg> esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg;
|
2014-02-24 01:00:42 +01:00
|
|
|
|
2014-01-19 11:52:30 +01:00
|
|
|
struct CellDmuxEsCb
|
|
|
|
|
{
|
|
|
|
|
// CellDmuxCbEsMsg callback
|
2014-02-24 01:00:42 +01:00
|
|
|
be_t<u32> cbEsMsgFunc;
|
2014-01-19 11:52:30 +01:00
|
|
|
be_t<u32> cbArg_addr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxAttr
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> memSize;
|
|
|
|
|
be_t<u32> demuxerVerUpper;
|
|
|
|
|
be_t<u32> demuxerVerLower;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxEsAttr
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> memSize;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxEsResource
|
|
|
|
|
{
|
2014-02-23 17:52:52 +01:00
|
|
|
be_t<u32> memAddr;
|
|
|
|
|
be_t<u32> memSize;
|
2014-01-19 11:52:30 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxAuInfo
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> auAddr;
|
|
|
|
|
be_t<u32> auSize;
|
|
|
|
|
be_t<u32> auMaxSize;
|
2014-02-23 17:52:52 +01:00
|
|
|
be_t<u64> userData;
|
2014-01-19 11:52:30 +01:00
|
|
|
be_t<u32> ptsUpper;
|
|
|
|
|
be_t<u32> ptsLower;
|
|
|
|
|
be_t<u32> dtsUpper;
|
|
|
|
|
be_t<u32> dtsLower;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellDmuxAuInfoEx
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> auAddr;
|
|
|
|
|
be_t<u32> auSize;
|
|
|
|
|
be_t<u32> reserved;
|
2014-01-23 19:40:49 +01:00
|
|
|
bool isRap;
|
2014-01-19 11:52:30 +01:00
|
|
|
be_t<u64> userData;
|
2014-01-23 19:40:49 +01:00
|
|
|
CellCodecTimeStamp pts;
|
|
|
|
|
CellCodecTimeStamp dts;
|
2014-02-24 01:00:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Demuxer Thread Classes */
|
|
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
/* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */
|
|
|
|
|
|
|
|
|
|
PACKET_START_CODE_MASK = 0xffffff00,
|
|
|
|
|
PACKET_START_CODE_PREFIX = 0x00000100,
|
|
|
|
|
|
|
|
|
|
USER_DATA_START_CODE = 0x000001b2,
|
|
|
|
|
SEQUENCE_START_CODE = 0x000001b3,
|
|
|
|
|
EXT_START_CODE = 0x000001b5,
|
|
|
|
|
SEQUENCE_END_CODE = 0x000001b7,
|
|
|
|
|
GOP_START_CODE = 0x000001b8,
|
|
|
|
|
ISO_11172_END_CODE = 0x000001b9,
|
|
|
|
|
PACK_START_CODE = 0x000001ba,
|
|
|
|
|
SYSTEM_HEADER_START_CODE = 0x000001bb,
|
|
|
|
|
PROGRAM_STREAM_MAP = 0x000001bc,
|
|
|
|
|
PRIVATE_STREAM_1 = 0x000001bd,
|
|
|
|
|
PADDING_STREAM = 0x000001be,
|
|
|
|
|
PRIVATE_STREAM_2 = 0x000001bf,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct DemuxerStream
|
2014-02-24 01:00:42 +01:00
|
|
|
{
|
|
|
|
|
u32 addr;
|
|
|
|
|
u32 size;
|
2014-02-26 08:51:00 +01:00
|
|
|
u64 userdata;
|
|
|
|
|
bool discontinuity;
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
bool get(T& out)
|
|
|
|
|
{
|
|
|
|
|
if (sizeof(T) > size) return false;
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
out = *(T*)Memory.VirtualToRealAddr(addr);
|
2014-02-26 08:51:00 +01:00
|
|
|
addr += sizeof(T);
|
|
|
|
|
size -= sizeof(T);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
2014-03-04 00:21:34 +01:00
|
|
|
bool peek(T& out, u32 shift = 0)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-04 00:21:34 +01:00
|
|
|
if (sizeof(T) + shift > size) return false;
|
2014-02-26 08:51:00 +01:00
|
|
|
|
2014-03-04 00:21:34 +01:00
|
|
|
out = *(T*)Memory.VirtualToRealAddr(addr + shift);
|
2014-02-26 08:51:00 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void skip(u32 count)
|
|
|
|
|
{
|
|
|
|
|
addr += count;
|
|
|
|
|
size = size > count ? size - count : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
u64 get_ts(u8 c)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
u8 v[4]; get((u32&)v);
|
|
|
|
|
return
|
|
|
|
|
(((u64)c & 0x0e) << 29) |
|
|
|
|
|
(((u64)v[0]) << 21) |
|
|
|
|
|
(((u64)v[1] & 0x7e) << 15) |
|
|
|
|
|
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
u64 get_ts()
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
|
|
|
|
u8 v; get(v);
|
|
|
|
|
return get_ts(v);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct PesHeader
|
|
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
u64 pts;
|
|
|
|
|
u64 dts;
|
2014-02-26 08:51:00 +01:00
|
|
|
u8 size;
|
2014-03-01 09:38:50 +01:00
|
|
|
bool new_au;
|
2014-02-26 08:51:00 +01:00
|
|
|
|
|
|
|
|
PesHeader(DemuxerStream& stream)
|
2014-03-01 09:38:50 +01:00
|
|
|
: pts(0xffffffffffffffff)
|
|
|
|
|
, dts(0xffffffffffffffff)
|
2014-02-26 08:51:00 +01:00
|
|
|
, size(0)
|
2014-03-03 00:02:42 +01:00
|
|
|
, new_au(false)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
|
|
|
|
u16 header;
|
|
|
|
|
stream.get(header);
|
|
|
|
|
stream.get(size);
|
|
|
|
|
if (size)
|
|
|
|
|
{
|
2014-03-04 00:21:34 +01:00
|
|
|
u8 empty = 0;
|
2014-02-26 08:51:00 +01:00
|
|
|
u8 v;
|
2014-03-04 00:21:34 +01:00
|
|
|
while (true)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-04 00:21:34 +01:00
|
|
|
stream.get(v);
|
|
|
|
|
if (v != 0xFF) break; // skip padding bytes
|
|
|
|
|
empty++;
|
2014-03-13 10:17:45 +01:00
|
|
|
if (empty == size) return;
|
2014-03-04 00:21:34 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
|
|
|
|
|
{
|
|
|
|
|
new_au = true;
|
|
|
|
|
pts = stream.get_ts(v);
|
|
|
|
|
stream.skip(size - empty - 5);
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
2014-03-04 00:21:34 +01:00
|
|
|
else
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-04 00:21:34 +01:00
|
|
|
new_au = true;
|
|
|
|
|
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("PesHeader(): pts not found");
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
}
|
|
|
|
|
pts = stream.get_ts(v);
|
|
|
|
|
stream.get(v);
|
|
|
|
|
if ((v & 0xF0) != 0x10)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("PesHeader(): dts not found");
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
}
|
|
|
|
|
dts = stream.get_ts(v);
|
|
|
|
|
stream.skip(size - empty - 10);
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-24 01:00:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ElementaryStream;
|
|
|
|
|
|
|
|
|
|
enum DemuxerJobType
|
|
|
|
|
{
|
|
|
|
|
dmuxSetStream,
|
|
|
|
|
dmuxResetStream,
|
2014-02-26 08:51:00 +01:00
|
|
|
dmuxResetStreamAndWaitDone,
|
2014-02-24 01:00:42 +01:00
|
|
|
dmuxEnableEs,
|
|
|
|
|
dmuxDisableEs,
|
|
|
|
|
dmuxResetEs,
|
|
|
|
|
dmuxFlushEs,
|
|
|
|
|
dmuxClose,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct DemuxerTask
|
|
|
|
|
{
|
|
|
|
|
DemuxerJobType type;
|
|
|
|
|
|
|
|
|
|
union
|
|
|
|
|
{
|
2014-02-26 08:51:00 +01:00
|
|
|
DemuxerStream stream;
|
2014-02-24 01:00:42 +01:00
|
|
|
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
u32 es;
|
|
|
|
|
u32 auInfo_ptr_addr;
|
|
|
|
|
u32 auSpec_ptr_addr;
|
|
|
|
|
ElementaryStream* es_ptr;
|
2014-02-26 08:51:00 +01:00
|
|
|
} es;
|
2014-02-24 01:00:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DemuxerTask()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DemuxerTask(DemuxerJobType type)
|
|
|
|
|
: type(type)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Demuxer
|
|
|
|
|
{
|
|
|
|
|
public:
|
2014-03-13 10:17:45 +01:00
|
|
|
SQueue<DemuxerTask, 32> job;
|
|
|
|
|
SQueue<u32, 16> fbSetStream;
|
2014-02-24 01:00:42 +01:00
|
|
|
const u32 memAddr;
|
|
|
|
|
const u32 memSize;
|
2014-02-26 08:51:00 +01:00
|
|
|
const u32 cbFunc;
|
2014-02-24 01:00:42 +01:00
|
|
|
const u32 cbArg;
|
2014-02-26 08:51:00 +01:00
|
|
|
u32 id;
|
2014-03-01 09:38:50 +01:00
|
|
|
volatile bool is_finished;
|
|
|
|
|
volatile bool is_running;
|
2014-02-24 01:00:42 +01:00
|
|
|
|
2014-03-04 20:18:17 +01:00
|
|
|
CPUThread* dmuxCb;
|
2014-02-24 01:00:42 +01:00
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
Demuxer(u32 addr, u32 size, u32 func, u32 arg)
|
2014-02-24 01:00:42 +01:00
|
|
|
: is_finished(false)
|
2014-02-26 08:51:00 +01:00
|
|
|
, is_running(false)
|
2014-02-24 01:00:42 +01:00
|
|
|
, memAddr(addr)
|
|
|
|
|
, memSize(size)
|
|
|
|
|
, cbFunc(func)
|
|
|
|
|
, cbArg(arg)
|
2014-03-04 20:18:17 +01:00
|
|
|
, dmuxCb(nullptr)
|
2014-02-24 01:00:42 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ElementaryStream
|
|
|
|
|
{
|
2014-02-26 08:51:00 +01:00
|
|
|
SMutex mutex;
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
SQueue<u32> entries; // AU starting addresses
|
|
|
|
|
u32 put_count; // number of AU written
|
|
|
|
|
u32 released; // number of AU released
|
|
|
|
|
u32 peek_count; // number of AU obtained by GetAu(Ex)
|
|
|
|
|
|
|
|
|
|
u32 put; // AU that is being written now
|
|
|
|
|
u32 size; // number of bytes written (after 128b header)
|
|
|
|
|
//u32 first; // AU that will be released
|
|
|
|
|
//u32 peek; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex)
|
2014-03-13 10:17:45 +01:00
|
|
|
|
|
|
|
|
bool is_full()
|
|
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
if (released < put_count)
|
2014-03-13 10:17:45 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
u32 first = entries.Peek();
|
|
|
|
|
if (first >= put)
|
2014-03-13 10:17:45 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
return (first - put) < GetMaxAU();
|
2014-03-13 10:17:45 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// probably, always false
|
2014-03-22 02:08:25 +01:00
|
|
|
return (put + GetMaxAU()) > (memAddr + memSize);
|
2014-03-13 10:17:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-26 08:51:00 +01:00
|
|
|
|
2014-02-24 01:00:42 +01:00
|
|
|
public:
|
|
|
|
|
Demuxer* dmux;
|
2014-02-26 08:51:00 +01:00
|
|
|
u32 id;
|
2014-02-24 01:00:42 +01:00
|
|
|
const u32 memAddr;
|
|
|
|
|
const u32 memSize;
|
|
|
|
|
const u32 fidMajor;
|
|
|
|
|
const u32 fidMinor;
|
|
|
|
|
const u32 sup1;
|
|
|
|
|
const u32 sup2;
|
2014-02-26 08:51:00 +01:00
|
|
|
const u32 cbFunc;
|
2014-02-24 01:00:42 +01:00
|
|
|
const u32 cbArg;
|
|
|
|
|
const u32 spec; //addr
|
|
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, u32 cbFunc, u32 cbArg, u32 spec)
|
2014-02-24 01:00:42 +01:00
|
|
|
: dmux(dmux)
|
2014-03-04 00:21:34 +01:00
|
|
|
, memAddr(a128(addr))
|
|
|
|
|
, memSize(size - (addr - memAddr))
|
2014-02-24 01:00:42 +01:00
|
|
|
, fidMajor(fidMajor)
|
|
|
|
|
, fidMinor(fidMinor)
|
|
|
|
|
, sup1(sup1)
|
|
|
|
|
, sup2(sup2)
|
|
|
|
|
, cbFunc(cbFunc)
|
|
|
|
|
, cbArg(cbArg)
|
|
|
|
|
, spec(spec)
|
2014-03-22 02:08:25 +01:00
|
|
|
//, first(0)
|
|
|
|
|
//, peek(0)
|
|
|
|
|
, put(memAddr)
|
|
|
|
|
, size(0)
|
|
|
|
|
, put_count(0)
|
|
|
|
|
, released(0)
|
|
|
|
|
, peek_count(0)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-13 10:17:45 +01:00
|
|
|
const u32 GetMaxAU() const
|
|
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
return (fidMajor == 0xbd) ? 4096 : 640 * 1024 + 128; // TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 freespace()
|
|
|
|
|
{
|
|
|
|
|
if (size > GetMaxAU())
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("es::freespace(): last_size too big (size=0x%x, max_au=0x%x)", size, GetMaxAU());
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return GetMaxAU() - size;
|
2014-03-13 10:17:45 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
bool hasunseen()
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
SMutexLocker lock(mutex);
|
|
|
|
|
return peek_count < put_count;
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
bool hasdata()
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
SMutexLocker lock(mutex);
|
|
|
|
|
return size;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-07 22:31:08 +01:00
|
|
|
bool isfull()
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-07 22:31:08 +01:00
|
|
|
SMutexLocker lock(mutex);
|
2014-03-13 10:17:45 +01:00
|
|
|
return is_full();
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void finish(DemuxerStream& stream) // not multithread-safe
|
|
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
u32 addr;
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
SMutexLocker lock(mutex);
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Write(">>> es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
|
|
|
|
|
|
|
|
|
|
addr = put;
|
|
|
|
|
/*if (!first)
|
|
|
|
|
{
|
|
|
|
|
first = put;
|
|
|
|
|
}
|
|
|
|
|
if (!peek)
|
|
|
|
|
{
|
|
|
|
|
peek = put;
|
|
|
|
|
}*/
|
2014-03-13 10:17:45 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
mem_ptr_t<CellDmuxAuInfo> info(put);
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Warning("es::finish(): (%s) size = 0x%x, info_addr=0x%x, pts = 0x%x",
|
|
|
|
|
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(),
|
|
|
|
|
//(u32)info->auSize, put, (u32)info->ptsLower);
|
2014-03-19 01:32:23 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
u32 new_addr = a128(put + 128 + size);
|
|
|
|
|
if ((new_addr + GetMaxAU()) > (memAddr + memSize))
|
|
|
|
|
{
|
|
|
|
|
put = memAddr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
put = new_addr;
|
|
|
|
|
}
|
|
|
|
|
size = 0;
|
|
|
|
|
|
|
|
|
|
put_count++;
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Write("<<< es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
2014-03-22 02:08:25 +01:00
|
|
|
if (!entries.Push(addr))
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
ConLog.Error("es::finish() aborted (no space)");
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
void push(DemuxerStream& stream, u32 sz, PesHeader& pes)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
|
|
|
|
SMutexLocker lock(mutex);
|
2014-03-07 22:31:08 +01:00
|
|
|
|
2014-03-13 10:17:45 +01:00
|
|
|
if (is_full())
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
ConLog.Error("es::push(): buffer is full");
|
2014-02-26 08:51:00 +01:00
|
|
|
Emu.Pause();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
u32 data_addr = put + 128 + size;
|
|
|
|
|
size += sz;
|
|
|
|
|
if (!Memory.Copy(data_addr, stream.addr, sz))
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
ConLog.Error("es::push(): data copying failed");
|
2014-02-27 19:25:32 +01:00
|
|
|
Emu.Pause();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-03-22 02:08:25 +01:00
|
|
|
stream.skip(sz);
|
2014-02-26 08:51:00 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
mem_ptr_t<CellDmuxAuInfoEx> info(put);
|
|
|
|
|
info->auAddr = put + 128;
|
|
|
|
|
info->auSize = size;
|
2014-03-04 00:21:34 +01:00
|
|
|
if (pes.new_au)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
info->dts.lower = (u32)pes.dts;
|
|
|
|
|
info->dts.upper = (u32)(pes.dts >> 32);
|
|
|
|
|
info->pts.lower = (u32)pes.pts;
|
|
|
|
|
info->pts.upper = (u32)(pes.pts >> 32);
|
2014-02-26 08:51:00 +01:00
|
|
|
info->isRap = false; // TODO: set valid value
|
|
|
|
|
info->reserved = 0;
|
|
|
|
|
info->userData = stream.userdata;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
mem_ptr_t<CellDmuxPamfAuSpecificInfoAvc> tail(put + sizeof(CellDmuxAuInfoEx));
|
2014-02-26 08:51:00 +01:00
|
|
|
tail->reserved1 = 0;
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
mem_ptr_t<CellDmuxAuInfo> inf(put + 64);
|
|
|
|
|
inf->auAddr = put + 128;
|
|
|
|
|
inf->auSize = size;
|
2014-03-04 00:21:34 +01:00
|
|
|
if (pes.new_au)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
inf->dtsLower = (u32)pes.dts;
|
|
|
|
|
inf->dtsUpper = (u32)(pes.dts >> 32);
|
|
|
|
|
inf->ptsLower = (u32)pes.pts;
|
|
|
|
|
inf->ptsUpper = (u32)(pes.pts >> 32);
|
2014-02-26 08:51:00 +01:00
|
|
|
inf->auMaxSize = 0; // ?????
|
|
|
|
|
inf->userData = stream.userdata;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-07 22:31:08 +01:00
|
|
|
bool release()
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
|
|
|
|
SMutexLocker lock(mutex);
|
2014-03-22 02:08:25 +01:00
|
|
|
//if (fidMajor != 0xbd) ConLog.Write(">>> es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
|
|
|
|
|
if (released >= put_count)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
ConLog.Error("es::release(): buffer is empty");
|
2014-03-07 22:31:08 +01:00
|
|
|
return false;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
u32 addr = entries.Peek();
|
|
|
|
|
|
|
|
|
|
mem_ptr_t<CellDmuxAuInfo> info(addr);
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Warning("es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
|
|
|
|
|
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, first, (u32)info->ptsLower);
|
2014-03-07 22:31:08 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
if (released >= peek_count)
|
2014-03-07 22:31:08 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
ConLog.Error("es::release(): buffer has not been seen yet");
|
2014-03-07 22:31:08 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
/*u32 new_addr = a128(info.GetAddr() + 128 + info->auSize);
|
|
|
|
|
|
|
|
|
|
if (new_addr == put)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
first = 0;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
2014-03-13 10:17:45 +01:00
|
|
|
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
first = memAddr;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
first = new_addr;
|
|
|
|
|
}*/
|
2014-03-07 22:31:08 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
released++;
|
|
|
|
|
if (!entries.Pop(addr))
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("es::release(): entries.Pop() aborted (no entries found)");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Write("<<< es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
|
2014-03-07 22:31:08 +01:00
|
|
|
return true;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
|
|
|
|
|
{
|
|
|
|
|
SMutexLocker lock(mutex);
|
2014-03-22 02:08:25 +01:00
|
|
|
//if (fidMajor != 0xbd) ConLog.Write(">>> es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
|
|
|
|
|
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
|
|
|
|
|
if (peek_count >= put_count) return false;
|
2014-02-26 08:51:00 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
if (peek_count < released)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("es::peek(): sequence error: peek_count < released (peek_count=%d, released=%d)", peek_count, released);
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 addr = entries.Peek(peek_count - released);
|
|
|
|
|
mem_ptr_t<CellDmuxAuInfo> info(addr);
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Warning("es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
|
|
|
|
|
//wxString(update_index ? "Get" : "Peek").wx_str(),
|
|
|
|
|
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, peek, (u32)info->ptsLower);
|
2014-03-19 01:32:23 +01:00
|
|
|
|
2014-03-22 02:08:25 +01:00
|
|
|
out_data = addr;
|
2014-02-26 08:51:00 +01:00
|
|
|
out_spec = out_data + sizeof(CellDmuxAuInfoEx);
|
|
|
|
|
if (no_ex) out_data += 64;
|
|
|
|
|
|
|
|
|
|
if (update_index)
|
|
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
/*u32 new_addr = a128(peek + 128 + info->auSize);
|
|
|
|
|
if (new_addr = put)
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
peek = 0;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
2014-03-13 10:17:45 +01:00
|
|
|
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
|
2014-02-26 08:51:00 +01:00
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
peek = memAddr;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-03-22 02:08:25 +01:00
|
|
|
peek = new_addr;
|
|
|
|
|
}*/
|
|
|
|
|
peek_count++;
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
2014-03-22 02:08:25 +01:00
|
|
|
|
|
|
|
|
//if (fidMajor != 0xbd) ConLog.Write("<<< es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
|
|
|
|
|
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
|
2014-02-26 08:51:00 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reset()
|
2014-02-24 01:00:42 +01:00
|
|
|
{
|
2014-02-26 08:51:00 +01:00
|
|
|
SMutexLocker lock(mutex);
|
2014-03-22 02:08:25 +01:00
|
|
|
//first = 0;
|
|
|
|
|
//peek = 0;
|
|
|
|
|
put = memAddr;
|
|
|
|
|
size = 0;
|
|
|
|
|
entries.Clear();
|
|
|
|
|
put_count = 0;
|
|
|
|
|
released = 0;
|
|
|
|
|
peek_count = 0;
|
2014-02-24 01:00:42 +01:00
|
|
|
}
|
2014-02-26 12:27:06 +01:00
|
|
|
};
|