Ffcc.cs 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474
  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. internal 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. try
  409. {
  410. Return = ffmpeg.av_read_frame(Decoder.Format, Decoder.Packet);
  411. }
  412. catch
  413. {
  414. Return = ffmpeg.AVERROR_EOF;
  415. }
  416. if (Return == ffmpeg.AVERROR_EOF)
  417. {
  418. goto EOF;
  419. }
  420. else
  421. {
  422. CheckReturn();
  423. }
  424. }
  425. //check for correct stream.
  426. while (Decoder.Packet->stream_index != Decoder.StreamIndex);
  427. Return = ffmpeg.avcodec_send_packet(Decoder.CodecContext, Decoder.Packet);
  428. ffmpeg.av_packet_unref(Decoder.Packet);
  429. CheckReturn();
  430. Return = ffmpeg.avcodec_receive_frame(Decoder.CodecContext, Decoder.Frame);
  431. }
  432. while (Return == ffmpeg.AVERROR(ffmpeg.EAGAIN));
  433. CheckReturn();
  434. }
  435. else if (Return == ffmpeg.AVERROR_EOF)
  436. {
  437. goto EOF;
  438. }
  439. else
  440. {
  441. CheckReturn();
  442. }
  443. }
  444. //check for frameskip, if enabled check if behind.
  445. while (FrameSkip && Behind);
  446. frame = *Decoder.Frame;
  447. return true;
  448. //end of file, check for loop and end.
  449. EOF:
  450. Loop();
  451. frame = *Decoder.Frame;
  452. return false;
  453. }
  454. private Task task;
  455. /// <summary>
  456. /// Dispose of all leaky varibles.
  457. /// </summary>
  458. public void Dispose() => Dispose(true);
  459. /// <summary>
  460. /// Same as Play but with a thread. Thread is terminated on Stop() or Dispose().
  461. /// </summary>
  462. public void PlayInTask(float volume = 1.0f, float pitch = 0.0f, float pan = 0.0f)
  463. {
  464. if (sourceToken == null)
  465. sourceToken = new CancellationTokenSource();
  466. if (cancellationToken == null)
  467. cancellationToken = sourceToken.Token;
  468. Play(volume, pitch, pan);
  469. task = new Task(NextinTask);
  470. task.Start();
  471. }
  472. private CancellationTokenSource sourceToken;
  473. private CancellationToken cancellationToken;
  474. /// <summary>
  475. /// For use in threads runs Next till done. To keep audio buffer fed. Or really good timing
  476. /// on video frames.
  477. /// </summary>
  478. private void NextinTask()
  479. {
  480. try
  481. {
  482. while (Mode == FfccMode.STATE_MACH && !cancellationToken.IsCancellationRequested && State != FfccState.DONE && !isDisposed)
  483. {
  484. lock (Decoder) //make the main thread wait if it accesses this class.
  485. {
  486. while (!isDisposed && !Ahead)
  487. {
  488. if (Next() < 0)
  489. break;
  490. }
  491. }
  492. Thread.Sleep(NextAsyncSleep); //delay checks
  493. }
  494. }
  495. //catch (ThreadAbortException)
  496. //{
  497. // disposeAll = true;//stop playing
  498. //}
  499. finally
  500. {
  501. Dispose(cancellationToken.IsCancellationRequested); // dispose of everything except audio encase it's still playing.
  502. }
  503. }
  504. /// <summary>
  505. /// Attempts to get 1 frame of Video, or refill Audio buffer.
  506. /// </summary>
  507. /// <returns>Returns -1 if missing stream or returns AVERROR or returns 0 if no problem.</returns>
  508. public int Next()
  509. {
  510. //if stream doesn't exist or stream is done, end
  511. if (Decoder.StreamIndex == -1 || State == FfccState.DONE)
  512. {
  513. return -1;
  514. }
  515. // read next frame(s)
  516. else
  517. {
  518. return Update(FfccState.READONE);
  519. }
  520. }
  521. /// <summary>
  522. /// Pause or Resume timer. WIP
  523. /// </summary>
  524. public void Pause()
  525. {
  526. if (Decoder.StreamIndex > -1)
  527. {
  528. if (Mode == FfccMode.STATE_MACH)
  529. {
  530. if (!timer.IsRunning)
  531. {
  532. timer.Stop();
  533. }
  534. else
  535. {
  536. timer.Start();
  537. }
  538. }
  539. }
  540. }
  541. /// <summary>
  542. /// Start playing Sound or Start FPS timer for Video
  543. /// </summary>
  544. /// <param name="volume">
  545. /// Volume, ranging from 0.0 (silence) to 1.0 (full volume). Volume during playback is scaled
  546. /// by SoundEffect.MasterVolume.
  547. /// </param>
  548. /// <param name="pitch">
  549. /// Pitch adjustment, ranging from -1.0 (down an octave) to 0.0 (no change) to 1.0 (up an octave).
  550. /// </param>
  551. /// <param name="pan">
  552. /// Panning, ranging from -1.0 (left speaker) to 0.0 (centered), 1.0 (right speaker).
  553. /// </param>
  554. public void Play(float volume = 1.0f, float pitch = 0.0f, float pan = 0.0f) // there are some videos without sound meh.
  555. {
  556. if (Decoder.StreamIndex > -1)
  557. {
  558. if (!timer.IsRunning && Mode == FfccMode.STATE_MACH && MediaType == AVMediaType.AVMEDIA_TYPE_VIDEO)
  559. {
  560. timer.Start();
  561. }
  562. if (DynamicSound != null && !DynamicSound.IsDisposed && AudioEnabled)
  563. {
  564. DynamicSound.Volume = volume;
  565. DynamicSound.Pitch = pitch;
  566. DynamicSound.Pan = pan;
  567. DynamicSound.Play();
  568. }
  569. if (SoundEffect != null && !SoundEffect.IsDisposed && AudioEnabled)
  570. {
  571. SoundEffectInstance.Volume = volume;
  572. SoundEffectInstance.Pitch = pitch;
  573. SoundEffectInstance.Pan = pan;
  574. SoundEffectInstance.Play();
  575. }
  576. }
  577. }
  578. /// <summary>
  579. /// Stop playing Sound or Stop the FPS timer for Video , and Dispose of Varibles
  580. /// </summary>
  581. public void Stop()
  582. {
  583. if (stopped)
  584. return;
  585. if (timer.IsRunning)
  586. {
  587. timer.Stop();
  588. timer.Reset();
  589. }
  590. if (DynamicSound != null && !DynamicSound.IsDisposed)
  591. {
  592. if (AudioEnabled)
  593. {
  594. DynamicSound.Stop();
  595. }
  596. DynamicSound.Dispose();
  597. }
  598. if (SoundEffectInstance != null && !SoundEffectInstance.IsDisposed)
  599. {
  600. if (AudioEnabled)
  601. {
  602. SoundEffectInstance.Stop();
  603. }
  604. SoundEffectInstance.Dispose();
  605. }
  606. if (SoundEffect != null && !SoundEffect.IsDisposed)
  607. {
  608. SoundEffect.Dispose();
  609. }
  610. if (task != null)
  611. {
  612. sourceToken.Cancel();
  613. }
  614. }
  615. /// <summary>
  616. /// Converts Frame to Texture with correct colorspace
  617. /// </summary>
  618. /// <returns>Texture2D</returns>
  619. public Texture2D Texture2D()
  620. {
  621. lock (Decoder)
  622. {
  623. Texture2D frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, Decoder.CodecContext->width, Decoder.CodecContext->height, false, SurfaceFormat.Color);
  624. const int bpp = 4;
  625. byte[] texBuffer = new byte[Decoder.CodecContext->width * Decoder.CodecContext->height * bpp];
  626. fixed (byte* ptr = &texBuffer[0])
  627. {
  628. byte*[] srcData = { ptr, null, null, null };
  629. int[] srcLinesize = { Decoder.CodecContext->width * bpp, 0, 0, 0 };
  630. // convert video frame to the RGB data
  631. ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize);
  632. }
  633. frameTex.SetData(texBuffer);
  634. return frameTex;
  635. }
  636. }
  637. private bool stopped = false;
  638. protected virtual void Dispose(bool disposing)
  639. {
  640. lock (Decoder)
  641. {
  642. if (disposing)
  643. {
  644. Stop();
  645. }
  646. if (!isDisposed)
  647. {
  648. State = FfccState.DONE;
  649. Mode = FfccMode.NOTINIT;
  650. if (disposing)
  651. {
  652. //Stop();
  653. // TODO: dispose managed state (managed objects).
  654. }
  655. // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
  656. // TODO: set large fields to null.
  657. if (DecodedMemoryStream != null)
  658. {
  659. DecodedMemoryStream.Dispose();
  660. }
  661. if (ConvertedData != null)
  662. {
  663. //Marshal.FreeHGlobal((IntPtr)ConvertedData);
  664. }
  665. //if (_intPtr != null)
  666. //{
  667. // Marshal.FreeHGlobal(_intPtr);
  668. //}
  669. ffmpeg.sws_freeContext(ScalerContext);
  670. if (ResampleContext != null)
  671. {
  672. ffmpeg.swr_close(ResampleContext);
  673. SwrContext* pResampleContext = ResampleContext;
  674. ffmpeg.swr_free(&pResampleContext);
  675. }
  676. ffmpeg.av_frame_unref(ResampleFrame);
  677. ffmpeg.av_free(ResampleFrame);
  678. if (_avio_ctx != null)
  679. {
  680. //ffmpeg.avio_close(avio_ctx); //CTD
  681. ffmpeg.av_free(_avio_ctx);
  682. }
  683. //if (avio_ctx_buffer != null)
  684. // ffmpeg.av_freep(avio_ctx_buffer); //throws exception
  685. // set to true to prevent multiple disposings
  686. isDisposed = true;
  687. //GC.Collect(); // donno if this really does much. was trying to make sure the memory i'm watching is what is really there.
  688. }
  689. }
  690. }
  691. /// <summary>
  692. /// throw new exception
  693. /// </summary>
  694. /// <param name="v">string of message</param>
  695. private static void die(string v) => throw new Exception(v.Trim('\0'));
  696. /// <summary>
  697. /// Compairs two numbers and returns the smallest
  698. /// </summary>
  699. /// <param name="a">number a</param>
  700. /// <param name="b">number b</param>
  701. /// <returns>smaller of two numbers</returns>
  702. private static int FFMIN(int a, int b) => a < b ? a : b;
  703. /// <summary>
  704. /// For reading data from a memory pointer as if it's a file.
  705. /// </summary>
  706. /// <param name="opaque">incoming data</param>
  707. /// <param name="buf">outgoing data</param>
  708. /// <param name="buf_size">outgoing buffer size</param>
  709. /// <returns>Total bytes read, or EOF</returns>
  710. private static int Read_packet(void* opaque, byte* buf, int buf_size)
  711. {
  712. Buffer_Data* bd = (Buffer_Data*)opaque;
  713. return bd->Read(buf, buf_size);
  714. }
  715. /// <summary>
  716. /// Converts FFMPEG error codes into a string.
  717. /// </summary>
  718. private string AvError(int ret)
  719. {
  720. ulong errbuff_size = 256;
  721. byte[] errbuff = new byte[errbuff_size];
  722. fixed (byte* ptr = &errbuff[0])
  723. {
  724. ffmpeg.av_strerror(ret, ptr, errbuff_size);
  725. }
  726. return Encoding.UTF8.GetString(errbuff).Trim('\0');
  727. }
  728. /// <summary>
  729. /// Throws exception if Ret is less than 0
  730. /// </summary>
  731. private int CheckReturn()
  732. {
  733. switch (Return)
  734. {
  735. case ffmpeg.AVERROR_OUTPUT_CHANGED:
  736. die($"The swr_context output ch_layout, sample_rate, sample_fmt must match outframe! {Return} - {AvError(Return)}");
  737. break;
  738. case ffmpeg.AVERROR_INPUT_CHANGED:
  739. die($"The swr_context input ch_layout, sample_rate, sample_fmt must match inframe! {Return} - {AvError(Return)}");
  740. break;
  741. default:
  742. if (Return < 0)
  743. {
  744. die($"{Return} - {AvError(Return)}");
  745. }
  746. break;
  747. }
  748. return Return;
  749. }
  750. /// <summary>
  751. /// reads the tags from metadata
  752. /// </summary>
  753. /// <param name="metadata">metadata from format or stream</param>
  754. private void GetTags(ref AVDictionary* metadata)
  755. {
  756. string val = "", key = "";
  757. AVDictionaryEntry* tag = null;
  758. while ((tag = ffmpeg.av_dict_get(metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
  759. {
  760. for (int i = 0; tag->value[i] != 0; i++)
  761. {
  762. val += (char)tag->value[i];
  763. }
  764. for (int i = 0; tag->key[i] != 0; i++)
  765. {
  766. key += (char)tag->key[i];
  767. }
  768. Metadata[key.ToUpper()] = val;
  769. if (key == "LOOPSTART" && int.TryParse(val, out _loopstart))
  770. { }
  771. key = "";
  772. val = "";
  773. }
  774. }
  775. /// <summary>
  776. /// Opens filename and init class.
  777. /// </summary>
  778. private void Init(string filename, AVMediaType mediatype = AVMediaType.AVMEDIA_TYPE_AUDIO, FfccMode mode = FfccMode.STATE_MACH, int loopstart = -1)
  779. {
  780. ffmpeg.av_log_set_level(ffmpeg.AV_LOG_PANIC);
  781. LOOPSTART = loopstart;
  782. State = FfccState.OPEN;
  783. Mode = mode;
  784. DecodedFileName = filename;
  785. MediaType = mediatype;
  786. Return = -1;
  787. ConvertedData = null;
  788. Update();
  789. }
  790. /// <summary>
  791. /// Sets up AVFormatContext to be able from the memory buffer.
  792. /// </summary>
  793. private void LoadFromRAM(Buffer_Data* bd)
  794. {
  795. _avio_ctx = null;
  796. _avio_ctx_buffer_size = 4096;
  797. int ret = 0;
  798. //_bufferData = new Buffer_Data
  799. //{
  800. // Header = buffer,
  801. // HeaderSize = buffer_size
  802. //};
  803. _avio_ctx_buffer = (byte*)ffmpeg.av_malloc((ulong)_avio_ctx_buffer_size);
  804. if (_avio_ctx_buffer == null)
  805. {
  806. ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
  807. return;
  808. }
  809. rf = new avio_alloc_context_read_packet(Read_packet);
  810. _avio_ctx = ffmpeg.avio_alloc_context(_avio_ctx_buffer, _avio_ctx_buffer_size, 0, bd, rf, null, null);
  811. if (_avio_ctx == null)
  812. {
  813. ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
  814. }
  815. Decoder._format->pb = _avio_ctx;
  816. Open();
  817. }
  818. /// <summary>
  819. /// Copies byte[] data to a Pointer. So it can be used with ffmpeg.
  820. /// </summary>
  821. /// <param name="data">incoming data</param>
  822. /// <param name="length">size of data</param>
  823. //private void LoadFromRAM(byte[] data, int length)
  824. //{
  825. // _intPtr = Marshal.AllocHGlobal(length);
  826. // Marshal.Copy(data, 0, _intPtr, length);
  827. // LoadFromRAM(_intPtr, length);
  828. //}
  829. /// <summary>
  830. /// Load sound from Memorystream into a SoundEFFect
  831. /// </summary>
  832. /// <param name="decodedStream">Memory Stream containing sound data</param>
  833. private void LoadSoundFromStream(ref MemoryStream decodedStream)
  834. {
  835. if (DecodedMemoryStream.Length > 0 && MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  836. {
  837. if (SoundEffect == null)
  838. {
  839. SoundEffect = new SoundEffect(decodedStream.GetBuffer(), 0, (int)decodedStream.Length, ResampleFrame->sample_rate, (AudioChannels)ResampleFrame->channels, 0, 0);
  840. SoundEffectInstance = SoundEffect.CreateInstance();
  841. if (LOOPSTART >= 0)
  842. {
  843. SoundEffectInstance.IsLooped = true;
  844. }
  845. }
  846. }
  847. }
  848. /// <summary>
  849. /// Add sound from byte[] to a DynamicSoundEFFectInstance, it can play while you give it more data.
  850. /// </summary>
  851. /// <param name="decodedStream">sound data</param>
  852. private void LoadSoundFromStream(ref byte[] buffer, int start, ref int length)
  853. {
  854. if (length > 0 && MediaType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  855. {
  856. if (DynamicSound == null)
  857. {
  858. //create instance here to set sample_rate and channels dynamicly
  859. DynamicSound = new DynamicSoundEffectInstance(ResampleFrame->sample_rate, (AudioChannels)ResampleFrame->channels);
  860. }
  861. DynamicSound.SubmitBuffer(buffer, 0, length);
  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 internal 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 internal 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. }