c# uwp binaryreader

c# - Manipular un Adaptive IInputStream(MPEG-DASH) sobre la marcha



uwp binaryreader (1)

Esta es la primera vez que hago una pregunta aquí y no pude encontrar nada en la función de búsqueda.

El problema:

Estoy recibiendo (a través de HttpClient ) un IInputStream (Segmentos MP4). El problema es que mi MediaPlayer no lo reproduce porque estos segmentos MP4 contienen un solo átomo que causa un error ERR_FILETYPE_NOT_SUPPORTED .

Entonces, si UUID | Position: moov -> trak -> mdia -> minf -> stbl -> stsd -> encv -> sinf -> schi -> uui manualmente este Atom ( UUID | Position: moov -> trak -> mdia -> minf -> stbl -> stsd -> encv -> sinf -> schi -> uui ) funciona perfectamente bien.

El problema es que, como tengo un flujo adaptable, tengo que modificar esos segmentos (aproximadamente 1250 por película) sobre la marcha antes de enviarlo a AdaptiveMediaSource, y no puedo hacer que esto funcione correctamente.

Código:

using System; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Text; using System.Threading.Tasks; using Windows.Storage.Streams; using static System.Diagnostics.Debug; namespace BlackMagic { public class EvilVoodooClass { private static readonly bool _commitFlag = false; /// <summary> /// MP4 File parser /// </summary> /// <param name="awsInputStream"></param> public static async Task<Stream> ParseFile(IInputStream awsInputStream) { int moovPos = 0, moovSize = 0; int trakPos = 0, trakSize = 0; int mdiaPos = 0, mdiaSize = 0; int minfPos = 0, minfSize = 0; int stblPos = 0, stblSize = 0; int stsdPos = 0, stsdSize = 0; int encvPos = 0, encvSize = 0; int sinfPos = 0, sinfSize = 0; int schiPos = 0, schiSize = 0; int uuidPos = 0, uuidSize = 0; var bufferSize = new Windows.Storage.Streams.Buffer(200000); var readBuffer = await awsInputStream.ReadAsync(bufferSize, 200000, InputStreamOptions.ReadAhead); var tempInputStream = readBuffer.AsStream(); var tempOutStream = readBuffer.AsStream(); WriteLine("Parsing segment... "); using (var br = new BinaryReader(tempInputStream)) { var originalFilelength = (int)br.BaseStream.Length; WriteLine($"original File length: {originalFilelength}"); br.BaseStream.Seek(4, SeekOrigin.Begin); if ("ftypiso6" == Encoding.ASCII.GetString(br.ReadBytes(8))) { FindAtom(br, 0, "moov", ref moovPos, ref moovSize); WriteLine($"found moov at position: {moovPos} / size: {moovSize}"); FindAtom(br, moovPos + 8, "trak", ref trakPos, ref trakSize); WriteLine($"found trak at position: {trakPos} / size: {trakSize}"); FindAtom(br, trakPos + 8, "mdia", ref mdiaPos, ref mdiaSize); WriteLine($"found mdiaPos at position: {mdiaPos} / size: {mdiaSize}"); FindAtom(br, moovPos + 8, "minf", ref minfPos, ref minfSize); WriteLine($"found minfPos at position: {minfPos} / size: {minfSize}"); FindAtom(br, minfPos + 8, "stbl", ref stblPos, ref stblSize); WriteLine($"found stblPos at position: {stblPos} / size: {stblSize}"); FindAtom(br, stblPos + 8, "stsd", ref stsdPos, ref stsdSize); WriteLine($"found stsdSize at position: {stsdPos} / size: {stsdSize}"); // Breakpoint FindAtom(br, stsdPos + 8, "encv", ref encvPos, ref encvSize); WriteLine($"found encvSize at position: {encvPos} / size: {encvSize}"); FindAtom(br, encvPos + 8, "sinf", ref sinfPos, ref sinfSize); WriteLine($"found sinfPos at position: {sinfPos} / size: {sinfSize}"); FindAtom(br, sinfPos + 8, "schi", ref schiPos, ref schiSize); WriteLine($"found schiSize at position: {schiPos} / size: {schiSize}"); FindAtom(br, schiPos, "uuid", ref uuidPos, ref uuidSize); WriteLine($"found UU--ID at position: {uuidPos} / size: {uuidSize}"); br.BaseStream.Seek(0, SeekOrigin.Begin); if (uuidPos == 0) { WriteLine(" [No UUID Atom found]"); return tempOutStream; } WriteLine("[UUID Atom found]"); if (!_commitFlag) return tempOutStream; WriteLine("Rewriting segments... "); try { br.BaseStream.Seek(moovPos, SeekOrigin.Begin); var uuidBuffer = br.ReadBytes(moovSize); if (BufferArrayFindTag(ref uuidBuffer, "uuid", ref uuidPos, ref uuidSize)) CleanUuid(ref uuidBuffer, uuidPos, uuidSize); UpdateUuidSize(ref uuidBuffer); using (var binWri = new BinaryWriter(tempOutStream)) { br.BaseStream.Seek(0, SeekOrigin.Begin); BufferedBinaryCopy(br, binWri, moovPos); if (uuidBuffer.Length > 8) binWri.Write(uuidBuffer); br.BaseStream.Seek(moovSize, SeekOrigin.Current); BufferedBinaryCopy(br, binWri, originalFilelength - (moovPos + moovSize)); } WriteLine("FIXED!"); return tempOutStream; } catch { WriteLine(" --FAILED--"); return tempOutStream; } } else { WriteLine("[No MP4 Segment] "); return tempOutStream; } } } public static bool BufferedBinaryCopy(BinaryReader source, BinaryWriter destination, int length) { const int iobufferSize = 32 * 1024 * 1024; var bytesLeft = length; while (bytesLeft > 0) { var bytesToRead = Math.Min(iobufferSize, bytesLeft); var buffer = source.ReadBytes(bytesToRead); bytesLeft -= buffer.Length; destination.Write(buffer); } return true; } public static bool FindAtom(BinaryReader br, int offset, string tag, ref int pos, ref int size) { try { br.BaseStream.Seek(offset, SeekOrigin.Begin); while (br.BaseStream.Position < br.BaseStream.Length - 8) { var tagdata = br.ReadBytes(4); Array.Reverse(tagdata); var tagsize = (int)BitConverter.ToUInt32(tagdata, 0); if (tagsize == 1) { var exdata = br.ReadBytes(4); Array.Reverse(exdata); tagsize = (tagsize << 32) + (int)BitConverter.ToUInt32(exdata, 0); } tagdata = br.ReadBytes(4); var tagname = Encoding.ASCII.GetString(tagdata); if (tagname == tag) { pos = (int)br.BaseStream.Position - 8; size = tagsize; return true; } if (tagsize == 0) return false; br.BaseStream.Seek(tagsize - 8, SeekOrigin.Current); } } catch (Exception ex) { WriteLine(ex.ToString()); } return false; } public static void CleanUuid(ref byte[] buffer, int pos, int size) { var lb = buffer.ToList(); lb.RemoveRange(pos, size); buffer = lb.ToArray(); } public static void UpdateUuidSize(ref byte[] buffer) { var bufferLength = buffer.Length; var tagsize = BitConverter.GetBytes(bufferLength); Array.Reverse(tagsize); var lb = buffer.ToList(); lb.RemoveRange(0, 4); lb.InsertRange(0, tagsize); buffer = lb.ToArray(); } public static bool RewriteFile(ref BinaryReader input, long udtaPos, long udtaSize, long metaPos, long metaSize, long xtraPos, long xtraSize) { var tempname = string.Format(@"{0}.txt", Guid.NewGuid()); using (var b = new BinaryWriter(File.Open("tempname", FileMode.Create, FileAccess.Read))) { //throw new NotImplementedException(); } return true; } public static bool BufferArrayFindTag(ref byte[] bb, string tag, ref int tagPos, ref int tagSize) { var pattern = Encoding.UTF8.GetBytes(tag); var byteIndex = BufferArrayIndexOf(bb, pattern); if (byteIndex < 0) return false; tagPos = byteIndex - 4; tagSize = (bb[byteIndex - 4] << 24) | (bb[byteIndex - 3] << 16) | (bb[byteIndex - 2] << 8) | bb[byteIndex - 1]; return true; } public static int BufferArrayIndexOf(byte[] data, byte[] pattern) { if (pattern.Length > data.Length) return -1; for (var i = 0; i < data.Length - pattern.Length; i++) { var found = !pattern.Where((t, j) => data[i + j] != t).Any(); if (found) return i; } return -1; } }

}

hm ... ¿Cómo podría resolver este problema? ¿alguna pista?


Creo que puedes implementar una clase Stream tú mismo. Cuando alguien lee su transmisión, lee el IInputStream original y lo manipula y devuelve el resultado a la persona que llama.

Por cierto, si agrega "using System.IO", será muy fácil convertir .NET Streams ao desde Windows Streams.