如何在 C# 中使用 ContentPushStream 播放块音频?

Posted

技术标签:

【中文标题】如何在 C# 中使用 ContentPushStream 播放块音频?【英文标题】:How to play chunk audio in C# with ContentPushStream? 【发布时间】:2019-06-21 11:47:43 【问题描述】:

我在内存中有一个属于视频文件的字节流。

请注意,字节流并不代表整个视频文件,而是我当时可用的以字节为单位的视频文件的一部分。 我希望能够在视频播放器上播放这个块,或者如果可以的话。但是,我想自己控制流的流动,因为我从不同的服务器接收视频源。

我们已经尝试了以下示例:

https://www.codeproject.com/Articles/820146/HTTP-Partial-Content-In-ASP-NET-Web-API-Video

在我的例子中,第一块文件下载并播放了音频。加载下一个块后,即使文件被更新,它也不会在播放器中更新。它需要合并块并更新播放器中的文件。请在此处找到代码 sn-p:

            int count = 0;
            long remainingBytes = end - start + 1;
            long position = start;
            byte[] buffer = new byte[ReadStreamBufferSize];

            byte[] temp = new byte[ReadStreamBufferSize];

            inputStream.Position = start;
            int item = 1;
            do
            
                try
                

                    byte[] byteAry = new byte[ReadStreamBufferSize];
                    if (System.IO.File.Exists("D:\\test\\pp" + item + ".wav"))
                        byteAry = System.IO.File.ReadAllBytes("D:\\test\\pp" + item + ".wav");
                    
                    else
                    
                        break;
                    
                    temp = temp.Concat(byteAry).ToArray();                    
                    inputStream = new MemoryStream(temp);

                    if (remainingBytes > ReadStreamBufferSize)
                        count = inputStream.Read(buffer, 0, ReadStreamBufferSize);
                    else
                        count = inputStream.Read(buffer, 0, (int)remainingBytes);
                    outputStream.Write(buffer, 0, count);
                
                catch (Exception error)
                
                    Debug.WriteLine(error);

                    break;
                
                position = inputStream.Position + 100;
                end = inputStream.Length;
                remainingBytes = end - position + 1;
                item++;
             while (position <= end);

【问题讨论】:

【参考方案1】:

您需要根据所有文件的大小重新创建 WAVE 文件头,然后附加音频数据,如下所示:

int item = 1;

var inputWaveFiles = new List<WaveFile>();

while (File.Exists($@"D:\test\ppitem.wav"))

    var waveFile = WaveFile.ReadWaveFile($@"D:\test\ppitem.wav");
    inputWaveFiles.Add(waveFile);
    item++;


WaveFile.Merge(inputWaveFiles, @"D:\test\output.wav");

public class WaveFile

    public string Path  get; set; 
    public int Length  get; set; 
    public short Channels  get; set; 
    public int SampleRate  get; set; 
    public int DataLength  get; set; 
    public short BitsPerSample  get; set; 

    private void WriteHeader(string filename)
    
        using (var file = new FileStream(filename, FileMode.Create, FileAccess.Write))
        
            using (var writer = new BinaryWriter(file))
            
                file.Position = 0;
                writer.Write(new char[4]  'R', 'I', 'F', 'F' );

                writer.Write(Length);

                writer.Write(new char[8]  'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' );

                writer.Write((int)16);

                writer.Write((short)1);
                writer.Write(Channels);

                writer.Write(SampleRate);

                writer.Write((int)(SampleRate * ((BitsPerSample * Channels) / 8)));

                writer.Write((short)((BitsPerSample * Channels) / 8));

                writer.Write(BitsPerSample);

                writer.Write(new char[4]  'd', 'a', 't', 'a' );
                writer.Write(DataLength);
            
        
    

    public static WaveFile ReadWaveFile(string filename)
    
        var waveFile = new WaveFile();
        waveFile.Path = filename;

        using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read))
        
            using (var reader = new BinaryReader(file))
            
                waveFile.Length = (int)file.Length - 8;
                file.Position = 22;
                waveFile.Channels = reader.ReadInt16();
                file.Position = 24;
                waveFile.SampleRate = reader.ReadInt32();
                file.Position = 34;
                waveFile.BitsPerSample = reader.ReadInt16();
                waveFile.DataLength = (int)file.Length - 44;
            
        
        return waveFile;
    

    public static void Merge(List<WaveFile> waveFiles, string outputFilename)
    
        var outputWave = new WaveFile();

        foreach(var waveFile in waveFiles)
        
            outputWave.DataLength += waveFile.DataLength;
            outputWave.Length += waveFile.Length;
        

        // Generate file with header (I just copy the sample rate etc.. from the first sound file)
        outputWave.BitsPerSample = waveFiles[0].BitsPerSample;
        outputWave.Channels = waveFiles[0].Channels;
        outputWave.SampleRate = waveFiles[0].SampleRate;
        outputWave.WriteHeader(outputFilename);

        // Append data
        foreach (var waveFile in waveFiles)
        
            // Read wave file
            using (var fileReader = new FileStream(waveFile.Path, FileMode.Open, FileAccess.Read))
            
                var inputData = new byte[fileReader.Length - 44];
                fileReader.Position = 44;
                fileReader.Read(inputData, 0, inputData.Length);

                // Write wave file
                using (var fileWriter = new FileStream(outputFilename, FileMode.Append, FileAccess.Write))
                
                    using (var writer = new BinaryWriter(fileWriter))
                    
                        writer.Write(inputData);
                    
                
            
        
    

参考文献

http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html

https://www.codeproject.com/Articles/15187/Concatenating-Wave-Files-Using-C-2005

【讨论】:

以上是关于如何在 C# 中使用 ContentPushStream 播放块音频?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中使用 libcinder?

如何在 C# 中使用 imageMagick

我如何在 webBrowser 中使用 c# 执行点击事件

如何使用 SMO 在存储过程中调用 c# 函数?

如何在打字稿中使用 C# 字典?

如何在 QT 项目中使用 C# 库?