Esempio n. 1
0
s32 cellSnd3SMFGetPlayVelocity(u32 smfID)
{
	throw EXCEPTION("");
}
Esempio n. 2
0
s32 BIG5stoUCS2s()
{
	throw EXCEPTION("");
}
Esempio n. 3
0
s32 UCS2toEUCJP()
{
	throw EXCEPTION("");
}
Esempio n. 4
0
s32 UCS2stoSBCSs()
{
	throw EXCEPTION("");
}
Esempio n. 5
0
s32 UCS2stoUHCs()
{
	throw EXCEPTION("");
}
Esempio n. 6
0
s32 JISstoUCS2s()
{
	throw EXCEPTION("");
}
Esempio n. 7
0
s32 ARIBstoUCS2s()
{
	throw EXCEPTION("");
}
Esempio n. 8
0
PesHeader::PesHeader(DemuxerStream& stream)
	: pts(CODEC_TS_INVALID)
	, dts(CODEC_TS_INVALID)
	, size(0)
	, has_ts(false)
	, is_ok(false)
{
	u16 header;
	if (!stream.get(header))
	{
		throw EXCEPTION("End of stream (header)");
	}
	if (!stream.get(size))
	{
		throw EXCEPTION("End of stream (size)");
	}
	if (!stream.check(size))
	{
		throw EXCEPTION("End of stream (size=%d)", size);
	}
	
	u8 pos = 0;
	while (pos++ < size)
	{
		u8 v;
		if (!stream.get(v))
		{
			return; // should never occur
		}

		if (v == 0xff) // skip padding bytes
		{
			continue;
		}

		if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only
		{
			pos += 4;
			pts = stream.get_ts(v);
			has_ts = true;
		}
		else if ((v & 0xf0) == 0x30 && (size - pos) >= 9) // pts and dts
		{
			pos += 5;
			pts = stream.get_ts(v);
			stream.get(v);
			has_ts = true;

			if ((v & 0xf0) != 0x10)
			{
				cellDmux.error("PesHeader(): dts not found (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
				stream.skip(size - pos);
				return;
			}
			pos += 4;
			dts = stream.get_ts(v);
		}
		else
		{
			cellDmux.warning("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
			stream.skip(size - pos);
			pos = size;
			break;
		}
	}

	is_ok = true;
}
Esempio n. 9
0
void dmuxOpen(u32 dmux_id) // TODO: call from the constructor
{
	const auto sptr = idm::get<Demuxer>(dmux_id);
	Demuxer& dmux = *sptr;

	dmux.id = dmux_id;

	dmux.dmuxCb = idm::make_ptr<PPUThread>(fmt::format("Demuxer[0x%x] Thread", dmux_id));
	dmux.dmuxCb->prio = 1001;
	dmux.dmuxCb->stack_size = 0x10000;
	dmux.dmuxCb->custom_task = [sptr](PPUThread& CPU)
	{
		Demuxer& dmux = *sptr;

		DemuxerTask task;
		DemuxerStream stream = {};
		ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL));
		ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count)
		ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count)
		ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
		ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16)
		ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16)
		ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16)

		u32 cb_add = 0;

		while (true)
		{
			if (Emu.IsStopped() || dmux.is_closed)
			{
				break;
			}
			
			if (!dmux.job.try_peek(task) && dmux.is_running && stream.addr)
			{
				// default task (demuxing) (if there is no other work)
				be_t<u32> code;
				be_t<u16> len;

				if (!stream.peek(code)) 
				{
					// demuxing finished
					dmux.is_running = false;

					// callback
					auto dmuxMsg = vm::ptr<CellDmuxMsg>::make(dmux.memAddr + (cb_add ^= 16));
					dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
					dmuxMsg->supplementalInfo = stream.userdata;
					dmux.cbFunc(CPU, dmux.id, dmuxMsg, dmux.cbArg);

					dmux.is_working = false;

					stream = {};
					
					continue;
				}
				
				switch (code)
				{
				case PACK_START_CODE:
				{
					if (!stream.check(14))
					{
						throw EXCEPTION("End of stream (PACK_START_CODE)");
					}
					stream.skip(14);
					break;
				}

				case SYSTEM_HEADER_START_CODE:
				{
					if (!stream.check(18))
					{
						throw EXCEPTION("End of stream (SYSTEM_HEADER_START_CODE)");
					}
					stream.skip(18);
					break;
				}

				case PADDING_STREAM:
				{
					if (!stream.check(6))
					{
						throw EXCEPTION("End of stream (PADDING_STREAM)");
					}
					stream.skip(4);
					stream.get(len);

					if (!stream.check(len))
					{
						throw EXCEPTION("End of stream (PADDING_STREAM, len=%d)", len);
					}
					stream.skip(len);
					break;
				}

				case PRIVATE_STREAM_2:
				{
					if (!stream.check(6))
					{
						throw EXCEPTION("End of stream (PRIVATE_STREAM_2)");
					}
					stream.skip(4);
					stream.get(len);

					cellDmux.notice("PRIVATE_STREAM_2 (%d)", len);

					if (!stream.check(len))
					{
						throw EXCEPTION("End of stream (PRIVATE_STREAM_2, len=%d)", len);
					}
					stream.skip(len);
					break;
				}

				case PRIVATE_STREAM_1:
				{
					// audio and user data stream
					DemuxerStream backup = stream;

					if (!stream.check(6))
					{
						throw EXCEPTION("End of stream (PRIVATE_STREAM_1)");
					}
					stream.skip(4);
					stream.get(len);

					if (!stream.check(len))
					{
						throw EXCEPTION("End of stream (PRIVATE_STREAM_1, len=%d)", len);
					}

					const PesHeader pes(stream);
					if (!pes.is_ok)
					{
						throw EXCEPTION("PesHeader error (PRIVATE_STREAM_1, len=%d)", len);
					}

					if (len < pes.size + 4)
					{
						throw EXCEPTION("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len);
					}
					len -= pes.size + 4;
					
					u8 fid_minor;
					if (!stream.get(fid_minor))
					{
						throw EXCEPTION("End of stream (PRIVATE_STREAM1, fid_minor)");
					}

					const u32 ch = fid_minor % 16;
					if ((fid_minor & -0x10) == 0 && esATX[ch])
					{
						ElementaryStream& es = *esATX[ch];
						if (es.raw_data.size() > 1024 * 1024)
						{
							stream = backup;
							std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
							continue;
						}

						if (len < 3 || !stream.check(3))
						{
							throw EXCEPTION("End of block (ATX, unknown header, len=%d)", len);
						}
						len -= 3;
						stream.skip(3);

						if (pes.has_ts)
						{
							es.last_dts = pes.dts;
							es.last_pts = pes.pts;
						}

						es.push(stream, len);

						while (true)
						{
							auto const size = es.raw_data.size() - es.raw_pos; // size of available new data
							auto const data = es.raw_data.data() + es.raw_pos; // pointer to available data

							if (size < 8) break; // skip if cannot read ATS header

							if (data[0] != 0x0f || data[1] != 0xd0)
							{
								throw EXCEPTION("ATX: 0x0fd0 header not found (ats=0x%llx)", *(be_t<u64>*)data);
							}

							u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8;

							if (size < frame_size + 8) break; // skip non-complete AU

							if (es.isfull(frame_size + 8)) break; // skip if cannot push AU
							
							es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);

							//cellDmux.notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", *(be_t<u64>*)data, frame_size);

							auto esMsg = vm::ptr<CellDmuxEsMsg>::make(dmux.memAddr + (cb_add ^= 16));
							esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
							esMsg->supplementalInfo = stream.userdata;
							es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg);
						}
					}
					else
					{
						cellDmux.notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len, fid_minor);
						stream.skip(len);
					}
					break;
				}

				case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3:
				case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
				case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
				case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
				{
					// video stream (AVC or M2V)
					DemuxerStream backup = stream;

					if (!stream.check(6))
					{
						throw EXCEPTION("End of stream (video, code=0x%x)", code);
					}
					stream.skip(4);
					stream.get(len);

					if (!stream.check(len))
					{
						throw EXCEPTION("End of stream (video, code=0x%x, len=%d)", code, len);
					}

					const PesHeader pes(stream);
					if (!pes.is_ok)
					{
						throw EXCEPTION("PesHeader error (video, code=0x%x, len=%d)", code, len);
					}

					if (len < pes.size + 3)
					{
						throw EXCEPTION("End of block (video, code=0x%x, PesHeader)", code);
					}
					len -= pes.size + 3;

					const u32 ch = code % 16;
					if (esAVC[ch])
					{
						ElementaryStream& es = *esAVC[ch];

						const u32 old_size = (u32)es.raw_data.size();
						if (es.isfull(old_size))
						{
							stream = backup;
							std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
							continue;
						}

						if ((pes.has_ts && old_size) || old_size >= 0x69800)
						{
							// push AU if it becomes too big or the next packet contains PTS/DTS
							es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);

							// callback
							auto esMsg = vm::ptr<CellDmuxEsMsg>::make(dmux.memAddr + (cb_add ^= 16));
							esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
							esMsg->supplementalInfo = stream.userdata;
							es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg);
						}
						
						if (pes.has_ts)
						{
							// preserve dts/pts for next AU
							es.last_dts = pes.dts;
							es.last_pts = pes.pts;
						}

						// reconstruction of MPEG2-PS stream for vdec module
						const u32 size = len + pes.size + 9;
						stream = backup;
						es.push(stream, size);
					}
					else
					{
						cellDmux.notice("Video stream (code=0x%x, len=%d)", code, len);
						stream.skip(len);
					}
					break;
				}

				default:
				{
					if ((code & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX)
					{
						throw EXCEPTION("Unknown code found (0x%x)", code);
					}

					// search
					stream.skip(1);
				}
				}

				continue;
			}

			// wait for task if no work
			if (!dmux.job.pop(task, &dmux.is_closed))
			{
				break; // Emu is stopped
			}

			switch (task.type)
			{
			case dmuxSetStream:
			{
				if (task.stream.discontinuity)
				{
					cellDmux.warning("dmuxSetStream (beginning)");
					for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
					{
						if (esALL[i])
						{
							esALL[i]->reset();
						}
					}
				}

				stream = task.stream;
				//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
					//stream.addr, stream.size, stream.discontinuity, stream.userdata);
				break;
			}

			case dmuxResetStream:
			case dmuxResetStreamAndWaitDone:
			{
				// demuxing stopped
				if (dmux.is_running.exchange(false))
				{
					// callback
					auto dmuxMsg = vm::ptr<CellDmuxMsg>::make(dmux.memAddr + (cb_add ^= 16));
					dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
					dmuxMsg->supplementalInfo = stream.userdata;
					dmux.cbFunc(CPU, dmux.id, dmuxMsg, dmux.cbArg);

					stream = {};

					dmux.is_working = false;
				}

				break;
			}

			case dmuxEnableEs:
			{
				ElementaryStream& es = *task.es.es_ptr;

				// TODO: uncomment when ready to use
				if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2)
				{
					esAVC[es.fidMajor % 16] = task.es.es_ptr;
				}
				//else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2)
				//{
				//	esM2V[es.fidMajor % 16] = task.es.es_ptr;
				//}
				else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2)
				{
					esATX[es.fidMinor % 16] = task.es.es_ptr;
				}
				//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2)
				//{
				//	esDATA[es.fidMinor % 16] = task.es.es_ptr;
				//}
				//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2)
				//{
				//	esAC3[es.fidMinor % 16] = task.es.es_ptr;
				//}
				//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2)
				//{
				//	esPCM[es.fidMinor % 16] = task.es.es_ptr;
				//}
				else
				{
					throw EXCEPTION("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
				}
				es.dmux = &dmux;
				break;
			}

			case dmuxDisableEs:
			{
				ElementaryStream& es = *task.es.es_ptr;
				if (es.dmux != &dmux)
				{
					throw EXCEPTION("dmuxDisableEs: invalid elementary stream");
				}

				for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
				{
					if (esALL[i] == &es)
					{
						esALL[i] = nullptr;
					}
				}
				es.dmux = nullptr;
				idm::remove<ElementaryStream>(task.es.es);
				break;
			}

			case dmuxFlushEs:
			{
				ElementaryStream& es = *task.es.es_ptr;

				const u32 old_size = (u32)es.raw_data.size();
				if (old_size && (es.fidMajor & -0x10) == 0xe0)
				{
					// TODO (it's only for AVC, some ATX data may be lost)
					while (es.isfull(old_size))
					{
						if (Emu.IsStopped() || dmux.is_closed) break;

						std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
					}

					es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0);

					// callback
					auto esMsg = vm::ptr<CellDmuxEsMsg>::make(dmux.memAddr + (cb_add ^= 16));
					esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
					esMsg->supplementalInfo = stream.userdata;
					es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg);
				}
				
				if (es.raw_data.size())
				{
					cellDmux.error("dmuxFlushEs: 0x%x bytes lost (es_id=%d)", (u32)es.raw_data.size(), es.id);
				}

				// callback
				auto esMsg = vm::ptr<CellDmuxEsMsg>::make(dmux.memAddr + (cb_add ^= 16));
				esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
				esMsg->supplementalInfo = stream.userdata;
				es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg);
				break;
			}

			case dmuxResetEs:
			{
				task.es.es_ptr->reset();
				break;
			}
			
			case dmuxClose:
			{
				break;
			}

			default:
			{
				throw EXCEPTION("Demuxer thread error: unknown task (0x%x)", task.type);
			}	
			}
		}

		dmux.is_finished = true;
	};

	dmux.dmuxCb->run();
	dmux.dmuxCb->exec();
}
Esempio n. 10
0
s32 cellSnd3NoteOnByTone(u32 hd3ID, u32 toneIndex, u32 note, u32 keyOnID, vm::ptr<CellSnd3KeyOnParam> keyOnParam)
{
	throw EXCEPTION("");
}
Esempio n. 11
0
s32 cellSnd3VoiceKeyOnByTone(u32 hd3ID, u32 voiceNum, u32 toneIndex, u32 pitch, u32 keyOnID, vm::ptr<CellSnd3KeyOnParam> keyOnParam)
{
	throw EXCEPTION("");
}
Esempio n. 12
0
s32 cellSnd3SMFGetPlayChannel(u32 smfID, vm::ptr<u32> playChannelBit)
{
	throw EXCEPTION("");
}
Esempio n. 13
0
s32 cellSnd3SMFGetPlayStatus(u32 smfID)
{
	throw EXCEPTION("");
}
Esempio n. 14
0
s32 cellSnd3SMFGetPlayPanpotEx(u32 smfID)
{
	throw EXCEPTION("");
}
Esempio n. 15
0
s32 eucjp2kuten()
{
	throw EXCEPTION("");
}
Esempio n. 16
0
s32 GB18030stoUTF8s()
{
	throw EXCEPTION("");
}
Esempio n. 17
0
s32 UTF8toBIG5()
{
	throw EXCEPTION("");
}
Esempio n. 18
0
s32 SJISstoEUCJPs()
{
	throw EXCEPTION("");
}
Esempio n. 19
0
s32 GB18030toUTF8()
{
	throw EXCEPTION("");
}
Esempio n. 20
0
s32 BIG5stoUTF8s()
{
	throw EXCEPTION("");
}
Esempio n. 21
0
s32 UCS2stoUTF32s()
{
	throw EXCEPTION("");
}
Esempio n. 22
0
s32 EUCCNtoUCS2()
{
	throw EXCEPTION("");
}
Esempio n. 23
0
s32 UCS2stoBIG5s()
{
	throw EXCEPTION("");
}
Esempio n. 24
0
s32 UCS2stoEUCKRs()
{
	throw EXCEPTION("");
}
Esempio n. 25
0
s32 SJIStoEUCJP()
{
	throw EXCEPTION("");
}
Esempio n. 26
0
s32 UTF8stoSJISs()
{
	throw EXCEPTION("");
}
Esempio n. 27
0
s32 UTF8stoUCS2s()
{
	throw EXCEPTION("");
}
Esempio n. 28
0
s32 UTF8stoHZs()
{
	throw EXCEPTION("");
}
Esempio n. 29
0
s32 l10n_convert()
{
	throw EXCEPTION("");
}
Esempio n. 30
0
u16 cellSnd3Pitch2Note(u16 center_note, u16 center_fine, u16 pitch)
{
	throw EXCEPTION("");
}