Ffcc.cs 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  1. namespace FF8
  2. {
  3. using FFmpeg.AutoGen;
  4. using Microsoft.Xna.Framework.Audio;
  5. using Microsoft.Xna.Framework.Graphics;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.IO;
  10. using System.Runtime.InteropServices;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. /// <summary>
  15. /// Ffcc is a front end for processing Audio and Video using ffmpeg.autogen
  16. /// </summary>
  17. /// <remarks>
  18. /// Code bits mostly converted to c# from c++ It uses bits of code from FFmpeg examples, Aforge,
  19. /// FFmpeg.autogen, stackoverflow
  20. /// </remarks>
  21. public unsafe class Ffcc : IDisposable
  22. {
  23. #region Fields
  24. /// <summary>
  25. /// If you have sound skipping increase this number and it'll go away. might decrease sync or
  26. /// increase memory load The goal is to keep the dynamicsoundeffectinterface fed. If it plays
  27. /// the audio before you give it more, then you get sound skips.
  28. /// </summary>
  29. /// <value>The goal buffer count.</value>
  30. /// <remarks>
  31. /// Will want to be as low as possible without sound skipping. 91.875 is 1 second of audio at
  32. /// 44100 hz @ 15 fps; 99.9001 is 1 second of audio at 48000 hz @ 15 fps;
  33. /// </remarks>
  34. private const int GoalBufferCount = 100;
  35. /// <summary>
  36. /// NextAsync sleeps when filling buffer. If set too high buffer will empty before filling it again.
  37. /// </summary>
  38. private const int NextAsyncSleep = 10;
  39. private readonly AVDictionary* _dict;
  40. private avio_alloc_context_read_packet rf;
  41. private AVIOContext* _avio_ctx;
  42. private byte* _avio_ctx_buffer;
  43. private int _avio_ctx_buffer_size;
  44. private byte[] _convertedData;
  45. //private byte* _convertedData;
  46. private MemoryStream _decodedMemoryStream;
  47. private bool _frameSkip = true;
  48. //private IntPtr _intPtr;
  49. private int _loopstart;
  50. public static string DataFileName;
  51. #endregion Fields
  52. #region Constructors
  53. /// <summary>
  54. /// Opens filename and init class.
  55. /// </summary>
  56. public Ffcc(string filename, AVMediaType mediatype = AVMediaType.AVMEDIA_TYPE_AUDIO, FfccMode mode = FfccMode.STATE_MACH, int loopstart = -1)
  57. {
  58. Init(filename, mediatype, mode, loopstart);
  59. if (mode == FfccMode.PROCESS_ALL)
  60. Dispose(false);
  61. }
  62. /// <summary>
  63. /// Opens filename and init class.
  64. /// </summary>
  65. /// <remarks>
  66. /// based on
  67. /// https://stackoverflow.com/questions/9604633/reading-a-file-located-in-memory-with-libavformat
  68. /// and http://www.ffmpeg.org/doxygen/trunk/doc_2examples_2avio_reading_8c-example.html and
  69. /// https://stackoverflow.com/questions/24758386/intptr-to-callback-function probably could
  70. /// be wrote better theres alot of hoops to jump threw
  71. /// </remarks>
  72. //public Ffcc(byte[] data, int length, AVMediaType mediatype = AVMediaType.AVMEDIA_TYPE_AUDIO, FfccMode mode = FfccMode.PROCESS_ALL, int loopstart = -1)
  73. //{
  74. //LoadFromRAM(data, length);
  75. //Init(null, mediatype, mode, loopstart);
  76. //}
  77. //public Ffcc(Buffer_Data* buffer_Data, string datafilename, AVMediaType mediatype, FfccMode mode, int loopstart = -1)
  78. //{
  79. // DataFileName = datafilename;
  80. // LoadFromRAM(buffer_Data);
  81. // Init(null, mediatype, mode, loopstart);
  82. //}
  83. public Ffcc(Buffer_Data buffer_Data, byte[] headerData, string datafilename, int loopstart = -1)
  84. {
  85. fixed (byte* tmp = &headerData[0])
  86. {
  87. lock (Decoder)
  88. {
  89. buffer_Data.SetHeader(tmp);
  90. DataFileName = datafilename;
  91. LoadFromRAM(&buffer_Data);
  92. Init(null, AVMediaType.AVMEDIA_TYPE_AUDIO, FfccMode.PROCESS_ALL, loopstart);
  93. ffmpeg.avformat_free_context(Decoder.Format);
  94. //ffmpeg.avio_context_free(&Decoder._format->pb); //CTD
  95. Decoder.Format = null;
  96. }
  97. Dispose(false);
  98. }
  99. }
  100. #endregion Constructors
  101. #region Destructors
  102. ~Ffcc()
  103. {
  104. Dispose();
  105. }
  106. #endregion Destructors
  107. #region Enums
  108. //public FileStream DecodeFileStream { get => _decodeFileStream; set => _decodeFileStream = value; }
  109. public enum FfccMode
  110. {
  111. /// <summary>
  112. /// Processes entire file at once and does something with output
  113. /// </summary>
  114. PROCESS_ALL,
  115. /// <summary>
  116. /// State machine, functions in this call update to update current state. And update
  117. /// decides what to do next.
  118. /// </summary>
  119. STATE_MACH,
  120. /// <summary>
  121. /// Not Init some error happened that prevented the class from working
  122. /// </summary>
  123. NOTINIT
  124. }
  125. public enum FfccState
  126. {
  127. OPEN,
  128. /// <summary>
  129. /// Waiting for request for next frame
  130. /// </summary>
  131. WAITING,
  132. /// <summary>
  133. /// Readall the data
  134. /// </summary>
  135. READALL,
  136. /// <summary>
  137. /// Done reading file nothing more can be done
  138. /// </summary>
  139. DONE,
  140. /// <summary>
  141. /// Don't change state just pass ret value.
  142. /// </summary>
  143. NULL,
  144. /// <summary>
  145. /// Get packet of data containing frames
  146. /// </summary>
  147. READONE,
  148. /// <summary>
  149. /// Missing DLL required to function
  150. /// </summary>
  151. NODLL,
  152. /// <summary>
  153. /// Gets stream and Codec
  154. /// </summary>
  155. GETCODEC,
  156. /// <summary>
  157. /// Prepares Scaler for Video stream
  158. /// </summary>
  159. PREPARE_SWS,
  160. /// <summary>
  161. /// Start Reading
  162. /// </summary>
  163. READ,
  164. /// <summary>
  165. /// Prepares Resampler for Audio stream
  166. /// </summary>
  167. PREPARE_SWR
  168. }
  169. #endregion Enums
  170. #region Properties
  171. /// <summary>
  172. /// Are you ahead of target frame
  173. /// </summary>
  174. /// <returns>true if ahead</returns>
  175. public bool Ahead
  176. {
  177. get
  178. {
  179. if (Decoder.StreamIndex != -1 && Mode == FfccMode.STATE_MACH)
  180. {
  181. if (MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  182. {
  183. if (DynamicSound != null)
  184. {
  185. return DynamicSound.PendingBufferCount > GoalBufferCount;
  186. }
  187. }
  188. else if (timer.IsRunning)
  189. {
  190. return CurrentFrameNum > ExpectedFrame;
  191. }
  192. }
  193. return true;
  194. }
  195. }
  196. /// <summary>
  197. /// Are you behind target frame
  198. /// </summary>
  199. /// <returns>true if behind</returns>
  200. public bool Behind => !Ahead && !Current;
  201. /// <summary>
  202. /// Are you on target frame
  203. /// </summary>
  204. /// <returns>true if correct frame</returns>
  205. public bool Current
  206. {
  207. get
  208. {
  209. if (Decoder.StreamIndex != -1 && Mode == FfccMode.STATE_MACH)
  210. {
  211. if (MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  212. {
  213. if (DynamicSound != null)
  214. {
  215. return DynamicSound.PendingBufferCount == GoalBufferCount;
  216. }
  217. else
  218. {
  219. die($"{Decoder.CodecContext->sample_rate} is currently unsupported");
  220. }
  221. }
  222. else if (timer.IsRunning)
  223. {
  224. return CurrentFrameNum == ExpectedFrame;
  225. }
  226. }
  227. return false;
  228. }
  229. }
  230. /// <summary>
  231. /// Path and filename of file.
  232. /// </summary>
  233. public string DecodedFileName { get; private set; }
  234. /// <summary>
  235. /// Dynamic Sound Effect Interface for class allows control out of class. Mode must be in STATE_MACH
  236. /// </summary>
  237. public DynamicSoundEffectInstance DynamicSound { get; private set; }
  238. /// <summary>
  239. /// True if file is open.
  240. /// </summary>
  241. public bool FileOpened { get; private set; }
  242. /// <summary>
  243. /// returns Frames per second or if that is 0. it will return the Time_Base ratio. This is
  244. /// the fundamental unit of time (in seconds) in terms of which frame timestamps are
  245. /// represented. In many cases the audio files time base is the same as the sample rate.
  246. /// example 1/44100. video files audio stream might be 1/100 or 1/1000. these can make for
  247. /// large durrations.
  248. /// </summary>
  249. public double FPS
  250. {
  251. get
  252. {
  253. double r = FPSvideo;
  254. if (r != 0)
  255. {
  256. return r;
  257. }
  258. else
  259. {
  260. if (MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO && Decoder.CodecContext != null && Decoder.CodecContext->framerate.den != 0)
  261. {
  262. return Decoder.CodecContext->framerate.num / (double)Decoder.CodecContext->framerate.den;
  263. }
  264. else if (Decoder.Stream != null && Decoder.Stream->time_base.den != 0)
  265. {
  266. return Decoder.Stream->time_base.num / (double)Decoder.Stream->time_base.den; // returns the time_base
  267. }
  268. }
  269. return 0;
  270. }
  271. }
  272. /// <summary>
  273. /// When getting video frames if behind it goes to next frame. disabled for debugging purposes.
  274. /// </summary>
  275. public bool FrameSkip { get => MediaType == AVMediaType.AVMEDIA_TYPE_VIDEO ? _frameSkip : false; set => _frameSkip = value; }
  276. /// <summary>
  277. /// Is the class disposed of. If true calling Dispose() does nothing.
  278. /// </summary>
  279. public bool isDisposed { get; private set; } = false;
  280. /// <summary>
  281. /// Sample count that loop starts from.
  282. /// </summary>
  283. public int LOOPSTART { get => _loopstart; set => _loopstart = value; }
  284. /// <summary>
  285. /// Current media type being processed.
  286. /// </summary>
  287. public AVMediaType MediaType { get; private set; }
  288. /// <summary>
  289. /// Metadata container for tags.
  290. /// </summary>
  291. public Dictionary<String, String> Metadata { get; private set; } = new Dictionary<string, string>();
  292. /// <summary>
  293. /// SoundEffect for class allows control out of class. Mode must be in PROCESS_ALL
  294. /// </summary>
  295. public SoundEffect SoundEffect { get; private set; }
  296. /// <summary>
  297. /// SoundEffectInterface for class. allows for more control than just playing the above soundeffect.
  298. /// </summary>
  299. public SoundEffectInstance SoundEffectInstance { get; private set; }
  300. /// <summary>
  301. /// Stopwatch tracks the time audio has played so video can sync or loops can be looped.
  302. /// </summary>
  303. public Stopwatch timer { get; } = new Stopwatch();
  304. /// <summary>
  305. /// if there is no stream it returns false. only checked when trying to process audio
  306. /// </summary>
  307. private bool AudioEnabled => Decoder.StreamIndex >= 0;
  308. //private byte* ConvertedData { get => _convertedData; set => _convertedData = value; }
  309. private byte[] ConvertedData { get => _convertedData; set => _convertedData = value; }
  310. /// <summary>
  311. /// Current frame number
  312. /// </summary>
  313. /// <returns>Current frame number or -1 on error</returns>
  314. private int CurrentFrameNum => Decoder.CodecContext != null ? Decoder.CodecContext->frame_number : -1;
  315. /// <summary>
  316. /// MemoryStream of Audio after decoding and resamping to compatable format.
  317. /// </summary>
  318. private MemoryStream DecodedMemoryStream { get => _decodedMemoryStream; set => _decodedMemoryStream = value; }
  319. /// <summary>
  320. /// Holder of varibles for Decoder
  321. /// </summary>
  322. private FfccVaribleGroup Decoder { get; set; } = new FfccVaribleGroup();
  323. /// <summary>
  324. /// Based on timer and FPS determines what the current frame is.
  325. /// </summary>
  326. /// <returns>Expected Frame Number</returns>
  327. private int ExpectedFrame => timer.IsRunning ? (int)Math.Round(timer.ElapsedMilliseconds * (FPS / 1000)) : 0;
  328. /// <summary>
  329. /// FPS of the video stream.
  330. /// </summary>
  331. private double FPSvideo
  332. {
  333. get
  334. {
  335. Return = ffmpeg.av_find_best_stream(Decoder.Format, AVMediaType.AVMEDIA_TYPE_VIDEO, -1, -1, null, 0);
  336. if (Return < 0)
  337. {
  338. return 0;
  339. }
  340. else if (Decoder.Format->streams[Return]->codec->framerate.den > 0)
  341. {
  342. return (double)Decoder.Format->streams[Return]->codec->framerate.num / Decoder.Format->streams[Return]->codec->framerate.den;
  343. }
  344. return 0;
  345. }
  346. }
  347. /// <summary>
  348. /// Mode that ffcc is running in.
  349. /// </summary>
  350. private FfccMode Mode { get; set; }
  351. /// <summary>
  352. /// Resample Context
  353. /// </summary>
  354. private SwrContext* ResampleContext { get; set; }
  355. /// <summary>
  356. /// Frame used by resampler
  357. /// </summary>
  358. private AVFrame* ResampleFrame { get; set; }
  359. /// <summary>
  360. /// Most ffmpeg functions return an integer. If the value is less than 0 it is an error
  361. /// usually. Sometimes data is passed and then it will be greater than 0.
  362. /// </summary>
  363. private int Return { get; set; }
  364. /// <summary>
  365. /// SWS Context
  366. /// </summary>
  367. private SwsContext* ScalerContext { get; set; }
  368. /// <summary>
  369. /// State ffcc is in.
  370. /// </summary>
  371. private FfccState State { get; set; }
  372. #endregion Properties
  373. #region Methods
  374. /// <summary>
  375. /// Flush the Decoder context and packet
  376. /// </summary>
  377. /// <param name="avctx">Decoder Codec Context</param>
  378. /// <param name="avpkt">Decoder Packet</param>
  379. /// <returns>0 on success, less than 0 on error</returns>
  380. public static int DecodeFlush(ref AVCodecContext* avctx, ref AVPacket avpkt)
  381. {
  382. avpkt.data = null;
  383. avpkt.size = 0;
  384. fixed (AVPacket* tmpPacket = &avpkt)
  385. {
  386. return ffmpeg.avcodec_send_packet(avctx, tmpPacket);
  387. }
  388. }
  389. /// <summary>
  390. /// Decode the next frame.
  391. /// </summary>
  392. /// <param name="frame">Current Decoded Frame</param>
  393. /// <returns>false if EOF, or true if grabbed frame</returns>
  394. public bool Decode(out AVFrame frame)
  395. {
  396. do
  397. {
  398. //need this extra receive frame for when decoding audio with >1 frame per packet
  399. Return = ffmpeg.avcodec_receive_frame(Decoder.CodecContext, Decoder.Frame);
  400. if (Return == ffmpeg.AVERROR(ffmpeg.EAGAIN))
  401. {
  402. do
  403. {
  404. do
  405. {
  406. //make sure packet is unref before getting a new one.
  407. ffmpeg.av_packet_unref(Decoder.Packet);
  408. Return = ffmpeg.av_read_frame(Decoder.Format, Decoder.Packet);
  409. if (Return == ffmpeg.AVERROR_EOF)
  410. {
  411. goto EOF;
  412. }
  413. else
  414. {
  415. CheckReturn();
  416. }
  417. }
  418. //check for correct stream.
  419. while (Decoder.Packet->stream_index != Decoder.StreamIndex);
  420. Return = ffmpeg.avcodec_send_packet(Decoder.CodecContext, Decoder.Packet);
  421. ffmpeg.av_packet_unref(Decoder.Packet);
  422. CheckReturn();
  423. Return = ffmpeg.avcodec_receive_frame(Decoder.CodecContext, Decoder.Frame);
  424. }
  425. while (Return == ffmpeg.AVERROR(ffmpeg.EAGAIN));
  426. CheckReturn();
  427. }
  428. else if (Return == ffmpeg.AVERROR_EOF)
  429. {
  430. goto EOF;
  431. }
  432. else
  433. {
  434. CheckReturn();
  435. }
  436. }
  437. //check for frameskip, if enabled check if behind.
  438. while (FrameSkip && Behind);
  439. frame = *Decoder.Frame;
  440. return true;
  441. //end of file, check for loop and end.
  442. EOF:
  443. Loop();
  444. frame = *Decoder.Frame;
  445. return false;
  446. }
  447. private Task task;
  448. /// <summary>
  449. /// Dispose of all leaky varibles.
  450. /// </summary>
  451. public void Dispose() => Dispose(true);
  452. /// <summary>
  453. /// Same as Play but with a thread. Thread is terminated on Stop() or Dispose().
  454. /// </summary>
  455. public void PlayInTask(float volume = 1.0f, float pitch = 0.0f, float pan = 0.0f)
  456. {
  457. if (sourceToken == null)
  458. sourceToken = new CancellationTokenSource();
  459. if (cancellationToken == null)
  460. cancellationToken = sourceToken.Token;
  461. Play(volume, pitch, pan);
  462. task = new Task(NextinTask);
  463. task.Start();
  464. }
  465. private CancellationTokenSource sourceToken;
  466. private CancellationToken cancellationToken;
  467. /// <summary>
  468. /// For use in threads runs Next till done. To keep audio buffer fed. Or really good timing
  469. /// on video frames.
  470. /// </summary>
  471. private void NextinTask()
  472. {
  473. try
  474. {
  475. while (Mode == FfccMode.STATE_MACH && !cancellationToken.IsCancellationRequested && State != FfccState.DONE && !isDisposed)
  476. {
  477. lock (Decoder) //make the main thread wait if it accesses this class.
  478. {
  479. while (!isDisposed && !Ahead)
  480. {
  481. if (Next() < 0)
  482. break;
  483. }
  484. }
  485. Thread.Sleep(NextAsyncSleep); //delay checks
  486. }
  487. }
  488. //catch (ThreadAbortException)
  489. //{
  490. // disposeAll = true;//stop playing
  491. //}
  492. finally
  493. {
  494. Dispose(cancellationToken.IsCancellationRequested); // dispose of everything except audio encase it's still playing.
  495. }
  496. }
  497. /// <summary>
  498. /// Attempts to get 1 frame of Video, or refill Audio buffer.
  499. /// </summary>
  500. /// <returns>Returns -1 if missing stream or returns AVERROR or returns 0 if no problem.</returns>
  501. public int Next()
  502. {
  503. //if stream doesn't exist or stream is done, end
  504. if (Decoder.StreamIndex == -1 || State == FfccState.DONE)
  505. {
  506. return -1;
  507. }
  508. // read next frame(s)
  509. else
  510. {
  511. return Update(FfccState.READONE);
  512. }
  513. }
  514. /// <summary>
  515. /// Pause or Resume timer. WIP
  516. /// </summary>
  517. public void Pause()
  518. {
  519. if (Decoder.StreamIndex > -1)
  520. {
  521. if (Mode == FfccMode.STATE_MACH)
  522. {
  523. if (!timer.IsRunning)
  524. {
  525. timer.Stop();
  526. }
  527. else
  528. {
  529. timer.Start();
  530. }
  531. }
  532. }
  533. }
  534. /// <summary>
  535. /// Start playing Sound or Start FPS timer for Video
  536. /// </summary>
  537. /// <param name="volume">
  538. /// Volume, ranging from 0.0 (silence) to 1.0 (full volume). Volume during playback is scaled
  539. /// by SoundEffect.MasterVolume.
  540. /// </param>
  541. /// <param name="pitch">
  542. /// Pitch adjustment, ranging from -1.0 (down an octave) to 0.0 (no change) to 1.0 (up an octave).
  543. /// </param>
  544. /// <param name="pan">
  545. /// Panning, ranging from -1.0 (left speaker) to 0.0 (centered), 1.0 (right speaker).
  546. /// </param>
  547. public void Play(float volume = 1.0f, float pitch = 0.0f, float pan = 0.0f) // there are some videos without sound meh.
  548. {
  549. if (Decoder.StreamIndex > -1)
  550. {
  551. if (!timer.IsRunning && Mode == FfccMode.STATE_MACH && MediaType == AVMediaType.AVMEDIA_TYPE_VIDEO)
  552. {
  553. timer.Start();
  554. }
  555. if (DynamicSound != null && !DynamicSound.IsDisposed && AudioEnabled)
  556. {
  557. DynamicSound.Volume = volume;
  558. DynamicSound.Pitch = pitch;
  559. DynamicSound.Pan = pan;
  560. DynamicSound.Play();
  561. }
  562. if (SoundEffect != null && !SoundEffect.IsDisposed && AudioEnabled)
  563. {
  564. SoundEffectInstance.Volume = volume;
  565. SoundEffectInstance.Pitch = pitch;
  566. SoundEffectInstance.Pan = pan;
  567. SoundEffectInstance.Play();
  568. }
  569. }
  570. }
  571. /// <summary>
  572. /// Stop playing Sound or Stop the FPS timer for Video , and Dispose of Varibles
  573. /// </summary>
  574. public void Stop()
  575. {
  576. if (stopped)
  577. return;
  578. if (timer.IsRunning)
  579. {
  580. timer.Stop();
  581. timer.Reset();
  582. }
  583. if (DynamicSound != null && !DynamicSound.IsDisposed)
  584. {
  585. if (AudioEnabled)
  586. {
  587. DynamicSound.Stop();
  588. }
  589. DynamicSound.Dispose();
  590. }
  591. if (SoundEffectInstance != null && !SoundEffectInstance.IsDisposed)
  592. {
  593. if (AudioEnabled)
  594. {
  595. SoundEffectInstance.Stop();
  596. }
  597. SoundEffectInstance.Dispose();
  598. }
  599. if (SoundEffect != null && !SoundEffect.IsDisposed)
  600. {
  601. SoundEffect.Dispose();
  602. }
  603. if (task != null)
  604. {
  605. sourceToken.Cancel();
  606. }
  607. }
  608. /// <summary>
  609. /// Converts Frame to Texture with correct colorspace
  610. /// </summary>
  611. /// <returns>Texture2D</returns>
  612. public Texture2D Texture2D()
  613. {
  614. lock (Decoder)
  615. {
  616. Texture2D frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, Decoder.CodecContext->width, Decoder.CodecContext->height, false, SurfaceFormat.Color);
  617. const int bpp = 4;
  618. byte[] texBuffer = new byte[Decoder.CodecContext->width * Decoder.CodecContext->height * bpp];
  619. fixed (byte* ptr = &texBuffer[0])
  620. {
  621. byte*[] srcData = { ptr, null, null, null };
  622. int[] srcLinesize = { Decoder.CodecContext->width * bpp, 0, 0, 0 };
  623. // convert video frame to the RGB data
  624. ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize);
  625. }
  626. frameTex.SetData(texBuffer);
  627. return frameTex;
  628. }
  629. }
  630. private bool stopped = false;
  631. protected virtual void Dispose(bool disposing)
  632. {
  633. lock (Decoder)
  634. {
  635. if (disposing)
  636. {
  637. Stop();
  638. }
  639. if (!isDisposed)
  640. {
  641. State = FfccState.DONE;
  642. Mode = FfccMode.NOTINIT;
  643. if (disposing)
  644. {
  645. //Stop();
  646. // TODO: dispose managed state (managed objects).
  647. }
  648. // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
  649. // TODO: set large fields to null.
  650. if (DecodedMemoryStream != null)
  651. {
  652. DecodedMemoryStream.Dispose();
  653. }
  654. if (ConvertedData != null)
  655. {
  656. //Marshal.FreeHGlobal((IntPtr)ConvertedData);
  657. }
  658. //if (_intPtr != null)
  659. //{
  660. // Marshal.FreeHGlobal(_intPtr);
  661. //}
  662. ffmpeg.sws_freeContext(ScalerContext);
  663. if (ResampleContext != null)
  664. {
  665. ffmpeg.swr_close(ResampleContext);
  666. SwrContext* pResampleContext = ResampleContext;
  667. ffmpeg.swr_free(&pResampleContext);
  668. }
  669. ffmpeg.av_frame_unref(ResampleFrame);
  670. ffmpeg.av_free(ResampleFrame);
  671. if (_avio_ctx != null)
  672. {
  673. //ffmpeg.avio_close(avio_ctx); //CTD
  674. ffmpeg.av_free(_avio_ctx);
  675. }
  676. //if (avio_ctx_buffer != null)
  677. // ffmpeg.av_freep(avio_ctx_buffer); //throws exception
  678. // set to true to prevent multiple disposings
  679. isDisposed = true;
  680. //GC.Collect(); // donno if this really does much. was trying to make sure the memory i'm watching is what is really there.
  681. }
  682. }
  683. }
  684. /// <summary>
  685. /// throw new exception
  686. /// </summary>
  687. /// <param name="v">string of message</param>
  688. private static void die(string v) => throw new Exception(v.Trim('\0'));
  689. /// <summary>
  690. /// Compairs two numbers and returns the smallest
  691. /// </summary>
  692. /// <param name="a">number a</param>
  693. /// <param name="b">number b</param>
  694. /// <returns>smaller of two numbers</returns>
  695. private static int FFMIN(int a, int b) => a < b ? a : b;
  696. /// <summary>
  697. /// For reading data from a memory pointer as if it's a file.
  698. /// </summary>
  699. /// <param name="opaque">incoming data</param>
  700. /// <param name="buf">outgoing data</param>
  701. /// <param name="buf_size">outgoing buffer size</param>
  702. /// <returns>Total bytes read, or EOF</returns>
  703. private static int Read_packet(void* opaque, byte* buf, int buf_size)
  704. {
  705. Buffer_Data* bd = (Buffer_Data*)opaque;
  706. return bd->Read(buf, buf_size);
  707. }
  708. /// <summary>
  709. /// Converts FFMPEG error codes into a string.
  710. /// </summary>
  711. private string AvError(int ret)
  712. {
  713. ulong errbuff_size = 256;
  714. byte[] errbuff = new byte[errbuff_size];
  715. fixed (byte* ptr = &errbuff[0])
  716. {
  717. ffmpeg.av_strerror(ret, ptr, errbuff_size);
  718. }
  719. return System.Text.Encoding.UTF8.GetString(errbuff).Trim('\0');
  720. }
  721. /// <summary>
  722. /// Throws exception if Ret is less than 0
  723. /// </summary>
  724. private int CheckReturn()
  725. {
  726. switch (Return)
  727. {
  728. case ffmpeg.AVERROR_OUTPUT_CHANGED:
  729. die($"The swr_context output ch_layout, sample_rate, sample_fmt must match outframe! {Return} - {AvError(Return)}");
  730. break;
  731. case ffmpeg.AVERROR_INPUT_CHANGED:
  732. die($"The swr_context input ch_layout, sample_rate, sample_fmt must match inframe! {Return} - {AvError(Return)}");
  733. break;
  734. default:
  735. if (Return < 0)
  736. {
  737. die($"{Return} - {AvError(Return)}");
  738. }
  739. break;
  740. }
  741. return Return;
  742. }
  743. /// <summary>
  744. /// reads the tags from metadata
  745. /// </summary>
  746. /// <param name="metadata">metadata from format or stream</param>
  747. private void GetTags(ref AVDictionary* metadata)
  748. {
  749. string val = "", key = "";
  750. AVDictionaryEntry* tag = null;
  751. while ((tag = ffmpeg.av_dict_get(metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
  752. {
  753. for (int i = 0; tag->value[i] != 0; i++)
  754. {
  755. val += (char)tag->value[i];
  756. }
  757. for (int i = 0; tag->key[i] != 0; i++)
  758. {
  759. key += (char)tag->key[i];
  760. }
  761. Metadata[key.ToUpper()] = val;
  762. if (key == "LOOPSTART" && int.TryParse(val, out _loopstart))
  763. { }
  764. key = "";
  765. val = "";
  766. }
  767. }
  768. /// <summary>
  769. /// Opens filename and init class.
  770. /// </summary>
  771. private void Init(string filename, AVMediaType mediatype = AVMediaType.AVMEDIA_TYPE_AUDIO, FfccMode mode = FfccMode.STATE_MACH, int loopstart = -1)
  772. {
  773. ffmpeg.av_log_set_level(ffmpeg.AV_LOG_PANIC);
  774. LOOPSTART = loopstart;
  775. State = FfccState.OPEN;
  776. Mode = mode;
  777. DecodedFileName = filename;
  778. MediaType = mediatype;
  779. Return = -1;
  780. ConvertedData = null;
  781. Update();
  782. }
  783. /// <summary>
  784. /// Sets up AVFormatContext to be able from the memory buffer.
  785. /// </summary>
  786. private void LoadFromRAM(Buffer_Data* bd)
  787. {
  788. _avio_ctx = null;
  789. _avio_ctx_buffer_size = 4096;
  790. int ret = 0;
  791. //_bufferData = new Buffer_Data
  792. //{
  793. // Header = buffer,
  794. // HeaderSize = buffer_size
  795. //};
  796. _avio_ctx_buffer = (byte*)ffmpeg.av_malloc((ulong)_avio_ctx_buffer_size);
  797. if (_avio_ctx_buffer == null)
  798. {
  799. ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
  800. return;
  801. }
  802. rf = new avio_alloc_context_read_packet(Read_packet);
  803. _avio_ctx = ffmpeg.avio_alloc_context(_avio_ctx_buffer, _avio_ctx_buffer_size, 0, bd, rf, null, null);
  804. if (_avio_ctx == null)
  805. {
  806. ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
  807. }
  808. Decoder._format->pb = _avio_ctx;
  809. Open();
  810. }
  811. /// <summary>
  812. /// Copies byte[] data to a Pointer. So it can be used with ffmpeg.
  813. /// </summary>
  814. /// <param name="data">incoming data</param>
  815. /// <param name="length">size of data</param>
  816. //private void LoadFromRAM(byte[] data, int length)
  817. //{
  818. // _intPtr = Marshal.AllocHGlobal(length);
  819. // Marshal.Copy(data, 0, _intPtr, length);
  820. // LoadFromRAM(_intPtr, length);
  821. //}
  822. /// <summary>
  823. /// Load sound from Memorystream into a SoundEFFect
  824. /// </summary>
  825. /// <param name="decodedStream">Memory Stream containing sound data</param>
  826. private void LoadSoundFromStream(ref MemoryStream decodedStream)
  827. {
  828. if (DecodedMemoryStream.Length > 0 && MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  829. {
  830. if (SoundEffect == null)
  831. {
  832. SoundEffect = new SoundEffect(decodedStream.GetBuffer(), 0, (int)decodedStream.Length, ResampleFrame->sample_rate, (AudioChannels)ResampleFrame->channels, 0, 0);
  833. SoundEffectInstance = SoundEffect.CreateInstance();
  834. if (LOOPSTART >= 0)
  835. {
  836. SoundEffectInstance.IsLooped = true;
  837. }
  838. }
  839. }
  840. }
  841. /// <summary>
  842. /// Add sound from byte[] to a DynamicSoundEFFectInstance, it can play while you give it more data.
  843. /// </summary>
  844. /// <param name="decodedStream">sound data</param>
  845. private void LoadSoundFromStream(ref byte[] buffer, int start, ref int length)
  846. {
  847. if (length > 0 && MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  848. {
  849. if (DynamicSound == null)
  850. {
  851. //create instance here to set sample_rate and channels dynamicly
  852. DynamicSound = new DynamicSoundEffectInstance(ResampleFrame->sample_rate, (AudioChannels)ResampleFrame->channels);
  853. }
  854. try
  855. {
  856. DynamicSound.SubmitBuffer(buffer, 0, length);
  857. }
  858. catch(ArgumentException)
  859. {
  860. //got error saying buffer was too small. makes no sense.
  861. }
  862. }
  863. }
  864. /// <summary>
  865. /// Load sound from memory stream by default.
  866. /// </summary>
  867. private void LoadSoundFromStream() => LoadSoundFromStream(ref _decodedMemoryStream);
  868. /// <summary>
  869. /// If looping seek back to LOOPSTART
  870. /// </summary>
  871. private void Loop()
  872. {
  873. if (LOOPSTART >= 0 && Mode == FfccMode.STATE_MACH)
  874. {
  875. int min = LOOPSTART - 1000;
  876. if (min < 0)
  877. {
  878. min = 0;
  879. }
  880. long max = Decoder.Stream->duration;
  881. if (max < 0)
  882. {
  883. max = LOOPSTART + 1000;
  884. }
  885. //I didn't realize this didn't change the framenumber to 0. it just appends the LOOPSTART pos to the current stream.
  886. //So it is possible this could overflow when it's looped long enough to bring the currentframenum to max value.
  887. Return = ffmpeg.avformat_seek_file(Decoder.Format, Decoder.StreamIndex, min, LOOPSTART, max, 0);
  888. CheckReturn();
  889. State = FfccState.WAITING;
  890. }
  891. }
  892. /// <summary>
  893. /// Opens filename and assigns FormatContext.
  894. /// </summary>
  895. private int Open()
  896. {
  897. if (!FileOpened)
  898. {
  899. fixed (AVFormatContext** tmp = &Decoder._format)
  900. {
  901. Return = ffmpeg.avformat_open_input(tmp, DecodedFileName, null, null);
  902. CheckReturn();
  903. }
  904. Return = ffmpeg.avformat_find_stream_info(Decoder.Format, null);
  905. CheckReturn();
  906. GetTags(ref Decoder.Format->metadata);
  907. FileOpened = true;
  908. }
  909. return (FileOpened) ? 0 : -1;
  910. }
  911. /// <summary>
  912. /// Finds the codec for the chosen stream
  913. /// </summary>
  914. private void PrepareCodec()
  915. {
  916. // find & open codec
  917. fixed (AVCodec** tmp = &Decoder._codec)
  918. {
  919. Return = ffmpeg.av_find_best_stream(Decoder.Format, MediaType, -1, -1, tmp, 0);
  920. }
  921. if (Return == ffmpeg.AVERROR_STREAM_NOT_FOUND && MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  922. {
  923. //Don't fail if no audiostream just be done.
  924. State = FfccState.DONE;
  925. Mode = FfccMode.NOTINIT;
  926. return;
  927. }
  928. else
  929. {
  930. CheckReturn();
  931. }
  932. Decoder.StreamIndex = Return;
  933. GetTags(ref Decoder.Stream->metadata);
  934. Decoder.CodecContext = ffmpeg.avcodec_alloc_context3(Decoder.Codec);
  935. if (Decoder.CodecContext == null)
  936. {
  937. die("Could not allocate codec context");
  938. }
  939. Return = ffmpeg.avcodec_parameters_to_context(Decoder.CodecContext, Decoder.Stream->codecpar);
  940. CheckReturn();
  941. fixed (AVDictionary** tmp = &_dict)
  942. {
  943. Return = ffmpeg.av_dict_set(tmp, "strict", "+experimental", 0);
  944. CheckReturn();
  945. Return = ffmpeg.avcodec_open2(Decoder.CodecContext, Decoder.Codec, tmp);
  946. CheckReturn();
  947. }
  948. if (MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  949. {
  950. if (Decoder.CodecContext->channel_layout == 0)
  951. {
  952. if (Decoder.CodecContext->channels == 2)
  953. {
  954. Decoder.CodecContext->channel_layout = ffmpeg.AV_CH_LAYOUT_STEREO;
  955. }
  956. else if (Decoder.CodecContext->channels == 1)
  957. {
  958. Decoder.CodecContext->channel_layout = ffmpeg.AV_CH_LAYOUT_MONO;
  959. }
  960. else
  961. {
  962. die("must set custom channel layout, is not stereo or mono");
  963. }
  964. }
  965. }
  966. }
  967. private void PrepareProcess()
  968. {
  969. using (DecodedMemoryStream = new MemoryStream())
  970. {
  971. Process();
  972. LoadSoundFromStream();
  973. }
  974. }
  975. /// <summary>
  976. /// PrepareResampler
  977. /// </summary>
  978. private void PrepareResampler()
  979. {
  980. if (MediaType != AVMediaType.AVMEDIA_TYPE_AUDIO)
  981. {
  982. return;
  983. }
  984. //resampler
  985. ResampleFrame = ffmpeg.av_frame_alloc();
  986. if (ResampleFrame == null)
  987. {
  988. die("Error allocating the frame\n");
  989. }
  990. ResampleContext = ffmpeg.swr_alloc();
  991. ffmpeg.av_opt_set_channel_layout(ResampleContext, "in_channel_layout", (long)Decoder.CodecContext->channel_layout, 0);
  992. ffmpeg.av_opt_set_int(ResampleContext, "in_sample_rate", Decoder.CodecContext->sample_rate, 0);
  993. ffmpeg.av_opt_set_sample_fmt(ResampleContext, "in_sample_fmt", Decoder.CodecContext->sample_fmt, 0);
  994. ffmpeg.av_opt_set_channel_layout(ResampleContext, "out_channel_layout", (long)Decoder.CodecContext->channel_layout, 0);
  995. ffmpeg.av_opt_set_sample_fmt(ResampleContext, "out_sample_fmt", AVSampleFormat.AV_SAMPLE_FMT_S16, 0);
  996. ffmpeg.av_opt_set_int(ResampleContext, "out_sample_rate", Decoder.CodecContext->sample_rate, 0);
  997. Return = ffmpeg.swr_init(ResampleContext);
  998. if (Return < 0)
  999. {
  1000. die("swr_init");
  1001. }
  1002. Decoder.Frame->format = (int)Decoder.CodecContext->sample_fmt;
  1003. Decoder.Frame->channel_layout = Decoder.CodecContext->channel_layout;
  1004. Decoder.Frame->channels = Decoder.CodecContext->channels;
  1005. Decoder.Frame->sample_rate = Decoder.CodecContext->sample_rate;
  1006. ResampleFrame->nb_samples = Decoder.CodecContext->frame_size;
  1007. if (ResampleFrame->nb_samples == 0)
  1008. {
  1009. ResampleFrame->nb_samples = 32; //32, or 64, ADPCM require 32.
  1010. }
  1011. ResampleFrame->format = (int)AVSampleFormat.AV_SAMPLE_FMT_S16;
  1012. ResampleFrame->channel_layout = Decoder.CodecContext->channel_layout;
  1013. ResampleFrame->channels = Decoder.CodecContext->channels;
  1014. ResampleFrame->sample_rate = Decoder.CodecContext->sample_rate;
  1015. int convertedFrameBufferSize = ffmpeg.av_samples_get_buffer_size(null, ResampleFrame->channels,
  1016. ResampleFrame->nb_samples,
  1017. (AVSampleFormat)ResampleFrame->format, 0);
  1018. //ConvertedData = (byte*)Marshal.AllocHGlobal(convertedFrameBufferSize);
  1019. ConvertedData = new byte[convertedFrameBufferSize];
  1020. }
  1021. /// <summary>
  1022. /// Setup scaler for drawing frames to bitmap.
  1023. /// </summary>
  1024. private void PrepareScaler()
  1025. {
  1026. if (MediaType != AVMediaType.AVMEDIA_TYPE_VIDEO)
  1027. {
  1028. return;
  1029. }
  1030. ScalerContext = ffmpeg.sws_getContext(
  1031. Decoder.CodecContext->width, Decoder.CodecContext->height, Decoder.CodecContext->pix_fmt,
  1032. Decoder.CodecContext->width, Decoder.CodecContext->height, AVPixelFormat.AV_PIX_FMT_RGBA,
  1033. ffmpeg.SWS_ACCURATE_RND, null, null, null);
  1034. Return = ffmpeg.sws_init_context(ScalerContext, null, null);
  1035. CheckReturn();
  1036. }
  1037. /// <summary>
  1038. /// Decodes, Resamples, Encodes
  1039. /// </summary>
  1040. /// <ref>https://stackoverflow.com/questions/32051847/c-ffmpeg-distorted-sound-when-converting-audio?rq=1#_=_</ref>
  1041. private void Process()
  1042. {
  1043. while (Decode(out AVFrame _DecodedFrame))
  1044. {
  1045. if (MediaType == AVMediaType.AVMEDIA_TYPE_VIDEO)
  1046. {
  1047. if (Mode == FfccMode.STATE_MACH)
  1048. {
  1049. State = FfccState.WAITING;
  1050. break;
  1051. }
  1052. // do something with video here.
  1053. else if (Mode == FfccMode.PROCESS_ALL)
  1054. {
  1055. }
  1056. }
  1057. else if (MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  1058. {
  1059. Resample(ref _DecodedFrame);
  1060. if (Mode == FfccMode.STATE_MACH && !Behind) //still behind stay here.
  1061. {
  1062. State = FfccState.WAITING;
  1063. break;
  1064. }
  1065. }
  1066. }
  1067. if (State != FfccState.WAITING)
  1068. {
  1069. State = FfccState.DONE;
  1070. timer.Stop();
  1071. timer.Reset();
  1072. DecodeFlush(ref Decoder._codecContext, ref *Decoder.Packet); //calling this twice was causing issues.
  1073. }
  1074. }
  1075. /// <summary>
  1076. /// Resample current frame, Save output data
  1077. /// </summary>
  1078. /// <param name="frame">Current Decoded Frame</param>
  1079. private void Resample(ref AVFrame frame)
  1080. {
  1081. // Convert
  1082. int outSamples = 0;
  1083. fixed (byte** tmp = (byte*[])frame.data)
  1084. {
  1085. outSamples = ffmpeg.swr_convert(ResampleContext, null, 0, tmp, frame.nb_samples);
  1086. }
  1087. if (outSamples < 0)
  1088. {
  1089. die("Could not convert");
  1090. }
  1091. for (; ; )
  1092. {
  1093. outSamples = ffmpeg.swr_get_out_samples(ResampleContext, 0);
  1094. // 32 was nb_samples but if too big would just not decode anything
  1095. if (outSamples < 32 * ResampleFrame->channels)
  1096. {
  1097. break;
  1098. }
  1099. //fixed (byte** tmp = &_convertedData)
  1100. fixed (byte* tmp = &_convertedData[0])
  1101. {
  1102. outSamples = ffmpeg.swr_convert(ResampleContext, &tmp, ResampleFrame->nb_samples, null, 0);
  1103. }
  1104. int buffer_size = ffmpeg.av_samples_get_buffer_size(null,
  1105. ResampleFrame->channels,
  1106. ResampleFrame->nb_samples,
  1107. (AVSampleFormat)ResampleFrame->format,
  1108. 0);
  1109. // write to buffer
  1110. WritetoMs(ref _convertedData, 0, ref buffer_size);
  1111. }
  1112. }
  1113. /// <summary>
  1114. /// Run code depending on state
  1115. /// </summary>
  1116. /// <param name="state">Change the state to this</param>
  1117. /// <param name="ret">return this</param>
  1118. /// <returns>ret</returns>
  1119. private int Update(FfccState state = FfccState.NULL, int ret = 0)
  1120. {
  1121. if (Mode == FfccMode.NOTINIT)
  1122. {
  1123. die("Class not Init");
  1124. }
  1125. if (state == FfccState.NODLL)
  1126. {
  1127. return -1;
  1128. }
  1129. if (state != FfccState.NULL)
  1130. {
  1131. State = state;
  1132. }
  1133. do
  1134. {
  1135. switch (State)
  1136. {
  1137. case FfccState.OPEN:
  1138. State = FfccState.GETCODEC;
  1139. if (0 < Open())
  1140. {
  1141. die("Failed to Open");
  1142. }
  1143. break;
  1144. case FfccState.GETCODEC:
  1145. State = FfccState.PREPARE_SWR;
  1146. PrepareCodec();
  1147. break;
  1148. case FfccState.PREPARE_SWR:
  1149. State = FfccState.PREPARE_SWS;
  1150. PrepareResampler();
  1151. break;
  1152. case FfccState.PREPARE_SWS:
  1153. State = FfccState.READ;
  1154. PrepareScaler();
  1155. break;
  1156. case FfccState.READ://Enters waiting state unless we want to process all now.
  1157. State = Mode == FfccMode.PROCESS_ALL ? FfccState.READALL : FfccState.READONE;
  1158. //READONE here makes it grab one video frame and precaches audio to it's limit.
  1159. //WAITING here makes it wait till GetFrame() is called.
  1160. //READALL just processes the whole audio stream (memoryleaky), not ment for video
  1161. //Currently video will just saves all the frames to bmp in temp folder on READALL.
  1162. break;
  1163. case FfccState.READALL:
  1164. State = FfccState.DONE;
  1165. PrepareProcess();
  1166. break;
  1167. case FfccState.READONE:
  1168. PrepareProcess();
  1169. switch (State)
  1170. {
  1171. case FfccState.WAITING:
  1172. ret = 0;
  1173. break;
  1174. default:
  1175. ret = -1;
  1176. break;
  1177. }
  1178. break;
  1179. default:
  1180. State = FfccState.DONE;
  1181. break;
  1182. }
  1183. }
  1184. while (!((Mode == FfccMode.PROCESS_ALL && State == FfccState.DONE) || (State == FfccState.DONE || State == FfccState.WAITING)));
  1185. return ret;
  1186. }
  1187. private int WritetoMs(ref byte[] output, int start, ref int length)
  1188. {
  1189. if (Mode == FfccMode.STATE_MACH)
  1190. {
  1191. LoadSoundFromStream(ref output, start, ref length);
  1192. }
  1193. else
  1194. {
  1195. DecodedMemoryStream.Write(output, start, length);
  1196. }
  1197. return length - start;
  1198. }
  1199. /// <summary>
  1200. /// Write to Memory Stream.
  1201. /// </summary>
  1202. /// <param name="output">Byte pointer to output buffer array</param>
  1203. /// <param name="start">Start from typically 0</param>
  1204. /// <param name="length">Total bytes to read.</param>
  1205. /// <returns>bytes wrote</returns>
  1206. private int WritetoMs(ref byte* output, int start, ref int length)
  1207. {
  1208. if (Mode == FfccMode.STATE_MACH)
  1209. {
  1210. byte[] arr = new byte[length];
  1211. Marshal.Copy((IntPtr)output, arr, 0, length);
  1212. LoadSoundFromStream(ref arr, start, ref length);
  1213. return length;
  1214. }
  1215. else
  1216. {
  1217. //memory leaky? seems when i used this method alot of memory wouldn't get disposed, might be only with large sounds
  1218. long c_len = DecodedMemoryStream.Length;
  1219. for (int i = start; i < length; i++)
  1220. {
  1221. DecodedMemoryStream.WriteByte(output[i]);
  1222. }
  1223. if (DecodedMemoryStream.Length - c_len != length)
  1224. {
  1225. die("not all data wrote");
  1226. }
  1227. return (int)(DecodedMemoryStream.Length - c_len);
  1228. }
  1229. }
  1230. #endregion Methods
  1231. #region Structs
  1232. /// <summary>
  1233. /// Used only when reading ADPCM data from memory.
  1234. /// </summary>
  1235. public struct Buffer_Data
  1236. {
  1237. #region Fields
  1238. public IntPtr Header;
  1239. public UInt32 HeaderSize;
  1240. public void SetHeader(IntPtr value) => Header = value;
  1241. public void SetHeader(byte* value) => Header = (IntPtr)value;
  1242. public UInt32 DataSeekLoc;
  1243. public UInt32 DataSize;
  1244. private unsafe int ReadHeader(byte* buf, int buf_size)
  1245. {
  1246. buf_size = FFMIN(buf_size, (int)HeaderSize);
  1247. if (buf_size == 0)
  1248. {
  1249. return ffmpeg.AVERROR_EOF;
  1250. }
  1251. // copy public buffer data to buf
  1252. Buffer.MemoryCopy((void*)Header, (void*)buf, buf_size, buf_size);
  1253. Header += buf_size;
  1254. HeaderSize -= (uint)buf_size;
  1255. return buf_size;
  1256. }
  1257. private unsafe int ReadData(byte* buf, int buf_size)
  1258. {
  1259. buf_size = FFMIN(buf_size, (int)DataSize);
  1260. if (buf_size == 0)
  1261. {
  1262. return ffmpeg.AVERROR_EOF;
  1263. }
  1264. using (FileStream fs = File.OpenRead(DataFileName))
  1265. {
  1266. fs.Seek(DataSeekLoc, SeekOrigin.Begin);
  1267. using (BinaryReader br = new BinaryReader(fs))
  1268. {
  1269. using (UnmanagedMemoryStream ums = new UnmanagedMemoryStream(buf, buf_size, buf_size, FileAccess.Write))
  1270. {
  1271. // copy public buffer data to buf
  1272. ums.Write(br.ReadBytes(buf_size), 0, buf_size);
  1273. DataSeekLoc += (uint)buf_size;
  1274. DataSize -= (uint)buf_size;
  1275. return buf_size;
  1276. }
  1277. }
  1278. }
  1279. }
  1280. public unsafe int Read(byte* buf, int buf_size)
  1281. {
  1282. int ret;
  1283. if ((ret = ReadHeader(buf, buf_size)) != ffmpeg.AVERROR_EOF)
  1284. return ret;
  1285. else
  1286. return ReadData(buf, buf_size);
  1287. }
  1288. //can't do this because soon as fixed block ends the pointer is no good.
  1289. //private void SetHeader(byte[] value)
  1290. //{
  1291. // fixed (byte* tmp = &value[0])
  1292. // {
  1293. // Header = (IntPtr)tmp;
  1294. // }
  1295. //}
  1296. #endregion Fields
  1297. //< size left in the buffer
  1298. };
  1299. #endregion Structs
  1300. }
  1301. }