You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

226 lines
9.5 KiB

using System;
using System.Collections.Generic;
using System.IO;
using VGMToolbox.util;
namespace VGMToolbox.format
{
public class CriUsmStream : MpegStream
{
public const string DefaultAudioExtension = ".adx";
public const string DefaultVideoExtension = ".m2v";
public const string HcaAudioExtension = ".hca";
static readonly byte[] HCA_SIG_BYTES = new byte[] { 0x48, 0x43, 0x41, 0x00 };
protected static readonly byte[] ALP_BYTES = new byte[] { 0x40, 0x41, 0x4C, 0x50 };
protected static readonly byte[] CRID_BYTES = new byte[] { 0x43, 0x52, 0x49, 0x44 };
protected static readonly byte[] SFV_BYTES = new byte[] { 0x40, 0x53, 0x46, 0x56 };
protected static readonly byte[] SFA_BYTES = new byte[] { 0x40, 0x53, 0x46, 0x41 };
protected static readonly byte[] SBT_BYTES = new byte[] { 0x40, 0x53, 0x42, 0x54 };
protected static readonly byte[] CUE_BYTES = new byte[] { 0x40, 0x43, 0x55, 0x45 };
protected static readonly byte[] UTF_BYTES = new byte[] { 0x40, 0x55, 0x54, 0x46 };
protected static readonly byte[] HEADER_END_BYTES =
new byte[] { 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20,
0x45, 0x4E, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x00 };
protected static readonly byte[] METADATA_END_BYTES =
new byte[] { 0x23, 0x4D, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54,
0x41, 0x20, 0x45, 0x4E, 0x44, 0x20, 0x20, 0x20,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x00 };
protected static readonly byte[] CONTENTS_END_BYTES =
new byte[] { 0x23, 0x43, 0x4F, 0x4E, 0x54, 0x45, 0x4E, 0x54,
0x53, 0x20, 0x45, 0x4E, 0x44, 0x20, 0x20, 0x20,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x00 };
public CriUsmStream(string path)
: base(path)
{
this.UsesSameIdForMultipleAudioTracks = true;
this.FileExtensionAudio = DefaultAudioExtension;
this.FileExtensionVideo = DefaultVideoExtension;
base.BlockIdDictionary.Clear();
base.BlockIdDictionary[BitConverter.ToUInt32(ALP_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @ALP
base.BlockIdDictionary[BitConverter.ToUInt32(CRID_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // CRID
base.BlockIdDictionary[BitConverter.ToUInt32(SFV_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SFV
base.BlockIdDictionary[BitConverter.ToUInt32(SFA_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SFA
base.BlockIdDictionary[BitConverter.ToUInt32(SBT_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SBT
base.BlockIdDictionary[BitConverter.ToUInt32(CUE_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @CUE
}
protected override byte[] GetPacketStartBytes() { return CRID_BYTES; }
protected override int GetAudioPacketHeaderSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "8";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override int GetVideoPacketHeaderSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "8";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override bool IsThisAnAudioBlock(byte[] blockToCheck)
{
return ParseFile.CompareSegment(blockToCheck, 0, SFA_BYTES);
}
protected override bool IsThisAVideoBlock(byte[] blockToCheck)
{
return ParseFile.CompareSegment(blockToCheck, 0, SFV_BYTES);
}
protected override byte GetStreamId(Stream readStream, long currentOffset)
{
byte streamId;
streamId = ParseFile.ParseSimpleOffset(readStream, currentOffset + 0xC, 1)[0];
return streamId;
}
protected override int GetAudioPacketFooterSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "0xA";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override int GetVideoPacketFooterSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "0xA";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override void DoFinalTasks(FileStream sourceFileStream, Dictionary<uint, FileStream> outputFiles, bool addHeader)
{
long headerEndOffset;
long metadataEndOffset;
long headerSize;
long footerOffset;
long footerSize;
string sourceFileName;
string workingFile;
string fileExtension;
string destinationFileName;
foreach (uint streamId in outputFiles.Keys)
{
sourceFileName = outputFiles[streamId].Name;
//--------------------------
// get header size
//--------------------------
headerEndOffset = ParseFile.GetNextOffset(outputFiles[streamId], 0, HEADER_END_BYTES);
metadataEndOffset = ParseFile.GetNextOffset(outputFiles[streamId], 0, METADATA_END_BYTES);
if (metadataEndOffset > headerEndOffset)
{
headerSize = metadataEndOffset + METADATA_END_BYTES.Length;
}
else
{
headerSize = headerEndOffset + METADATA_END_BYTES.Length;
}
//-----------------
// get footer size
//-----------------
footerOffset = ParseFile.GetNextOffset(outputFiles[streamId], 0, CONTENTS_END_BYTES) - headerSize;
footerSize = outputFiles[streamId].Length - footerOffset;
//------------------------------------------
// check data to adjust extension if needed
//------------------------------------------
if (this.IsThisAnAudioBlock(BitConverter.GetBytes(streamId & 0xFFFFFFF0))) // may need to change mask if more than 0xF streams
{
byte[] checkBytes = ParseFile.ParseSimpleOffset(outputFiles[streamId], headerSize, 4);
if (ParseFile.CompareSegment(checkBytes, 0, SofdecStream.AixSignatureBytes))
{
fileExtension = SofdecStream.AixAudioExtension;
}
else if (checkBytes[0] == 0x80)
{
fileExtension = SofdecStream.AdxAudioExtension;
}
else if (ParseFile.CompareSegment(checkBytes, 0, HCA_SIG_BYTES))
{
fileExtension = HcaAudioExtension;
}
else
{
fileExtension = ".bin";
}
this.FinalAudioExtension = fileExtension;
this.HasAudio = true;
}
else
{
fileExtension = Path.GetExtension(sourceFileName);
}
outputFiles[streamId].Close();
outputFiles[streamId].Dispose();
workingFile = FileUtil.RemoveChunkFromFile(sourceFileName, 0, headerSize);
File.Copy(workingFile, sourceFileName, true);
File.Delete(workingFile);
workingFile = FileUtil.RemoveChunkFromFile(sourceFileName, footerOffset, footerSize);
destinationFileName = Path.ChangeExtension(sourceFileName, fileExtension);
destinationFileName = destinationFileName.Substring(0, destinationFileName.LastIndexOf("_"))+fileExtension;
File.Copy(workingFile, destinationFileName, true);
File.Delete(workingFile);
if ((sourceFileName != destinationFileName) && (File.Exists(sourceFileName)))
{
File.Delete(sourceFileName);
}
}
}
}
}