BufferData.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using FFmpeg.AutoGen;
  2. using System;
  3. using System.IO;
  4. namespace OpenVIII.AV
  5. {
  6. /// <summary>
  7. /// Used only when reading ADPCM data from memory.
  8. /// </summary>
  9. public struct BufferData
  10. {
  11. #region Fields
  12. private IntPtr _header;
  13. private long _totalReadData;
  14. #endregion Fields
  15. #region Enums
  16. public enum TargetFile
  17. {
  18. SoundDat,
  19. OtherZzz
  20. }
  21. #endregion Enums
  22. #region Properties
  23. public static string DataFileName { get; set; }
  24. public long DataSeekLoc { get; set; }
  25. public long DataSize { get; set; }
  26. public uint HeaderSize { get; set; }
  27. public TargetFile Target { get; set; }
  28. #endregion Properties
  29. #region Methods
  30. public unsafe int Read(byte* buf, int bufSize)
  31. {
  32. int ret;
  33. if (HeaderSize > 0 && (ret = ReadHeader(buf, bufSize)) != ffmpeg.AVERROR_EOF)
  34. return ret;
  35. return ReadData(buf, bufSize);
  36. }
  37. public unsafe void SetHeader(byte* value) => _header = (IntPtr)value;
  38. internal long Seek(long offset, int whence)
  39. {
  40. switch (whence)
  41. {
  42. case ffmpeg.AVSEEK_SIZE:
  43. return offset == 0
  44. ? _totalReadData
  45. : throw new Exception($"unknown {nameof(whence)}: {whence}, {nameof(offset)}: {offset}");
  46. case 0:
  47. offset -= _totalReadData;
  48. break;
  49. default:
  50. throw new Exception($"unknown {nameof(whence)}: {whence}");
  51. }
  52. DataSeekLoc += offset;
  53. _totalReadData += offset;
  54. DataSize -= offset;
  55. return _totalReadData;
  56. }
  57. private unsafe int ReadData(byte* buf, int bufSize)
  58. {
  59. if (string.IsNullOrWhiteSpace(DataFileName))
  60. DataFileName = Path.Combine(Memory.FF8DirData, "Sound", "audio.dat");
  61. bufSize = Math.Min(bufSize, (int)DataSize);
  62. if (bufSize == 0)
  63. {
  64. return ffmpeg.AVERROR_EOF;
  65. }
  66. Stream s;
  67. ArchiveZzz other;
  68. switch (Target)
  69. {
  70. case TargetFile.SoundDat:
  71. if (File.Exists(DataFileName))
  72. {
  73. s = new FileStream(DataFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  74. }
  75. else
  76. {
  77. other = (ArchiveZzz)ArchiveZzz.Load(Memory.Archives.ZZZ_OTHER);
  78. s = new MemoryStream(other.GetBinaryFile("audio.dat", true), false);
  79. }
  80. break;
  81. case TargetFile.OtherZzz:
  82. other = (ArchiveZzz)ArchiveZzz.Load(Memory.Archives.ZZZ_OTHER);
  83. s = other.OpenStream();
  84. break;
  85. default:
  86. throw new ArgumentOutOfRangeException(
  87. $"{nameof(BufferData)}::{nameof(ReadData)}::{nameof(Target)} Value out of range! Target = {{{Target}}}");
  88. }
  89. // binaryReader disposes of fs
  90. if (s == null) throw new NullReferenceException($"{nameof(BufferData)}::{nameof(ReadData)} stream is null");
  91. using (var br = new BinaryReader(s))
  92. {
  93. s.Seek(DataSeekLoc, SeekOrigin.Begin);
  94. using (var ums = new UnmanagedMemoryStream(buf, bufSize, bufSize, FileAccess.Write))
  95. {
  96. // copy public buffer data to buf
  97. ums.Write(br.ReadBytes(bufSize), 0, bufSize);
  98. DataSeekLoc += bufSize;
  99. _totalReadData += bufSize;
  100. DataSize -= bufSize;
  101. return bufSize;
  102. }
  103. }
  104. }
  105. private unsafe int ReadHeader(byte* buf, int bufSize)
  106. {
  107. bufSize = Math.Min(bufSize, (int)HeaderSize);
  108. if (bufSize == 0)
  109. {
  110. return ffmpeg.AVERROR_EOF;
  111. }
  112. // copy public buffer data to buf
  113. Buffer.MemoryCopy((void*)_header, buf, bufSize, bufSize);
  114. _header += bufSize;
  115. HeaderSize -= (uint)bufSize;
  116. return bufSize;
  117. }
  118. #endregion Methods
  119. }
  120. }