如何在Silverlight 4 MediaStreamSource中同时读取和写入用于播放媒体文件的流?

时间:2011-03-06 22:00:30

标签: silverlight mediastreamsource

背景

我有一个媒体文件,我正在逐步下载到我的Silverlight 4应用程序,使用WebClient.OpenReadAsync / OpenReadCompleted和Stream.BeginRead / AsyncCallback。目标是通过调用SetSource方法在MediaElement中播放文件,传入我们的自定义MediaStreamSource的实例,以便文件可以在下载文件的整个内容之前开始播放。媒体文件使用自定义编码/解码,这就是我们使用自定义MediaStreamSource的原因。我们的MediaStreamSource构建为接受Stream并开始解析轨道信息并在MediaElement中播放。我已经确认我正在逐步下载文件内容。以下是下载代码的摘要:

public void SetSource(string sourceUrl)
{
    var uriBuilder = new UriBuilder(sourceUrl);
    WebClient webClient = new WebClient();

    // AllowReadStreamBuffering = false allows us to get the stream
    // before it's finished writing to it.
    webClient.AllowReadStreamBuffering = false;
    webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
    webClient.OpenReadAsync(uriBuilder.Uri);
}

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    _inboundVideoStream = e.Result;
    BeginReadingFromStream();
}

private void BeginReadingFromStream()
{
    if (_inboundVideoStream.CanRead)
    {
        _chunk = new byte[_chunkSize];
        _inboundVideoStream.BeginRead(_chunk, 0, _chunk.Length, new AsyncCallback(BeginReadCallback), _inboundVideoStream);
    }
}

private void BeginReadCallback(IAsyncResult asyncResult)
{
    Stream stream = asyncResult.AsyncState as Stream;
    int bytesRead = stream.EndRead(asyncResult);
    _totalBytesRead += bytesRead;

    if (_playableStream == null)
        _playableStream = new MemoryStream();

    _playableStream.Write(_chunk, 0, _chunk.Length);

    if (!_initializedMediaStream && _playableStream.Length >= _minimumToStartPlayback)
    {
        _initializedMediaStream = true;

        // Problem: we can't hand the stream source a stream that's still being written to
        // It's Position is at the end.  Can I read and write from the same stream or is there another way
        MP4MediaStreamSource streamSource = new MP4MediaStreamSource(_playableStream);

        this.Dispatcher.BeginInvoke(() =>
        {
            mediaElement1.SetSource(streamSource);
        });
    }

    if (_totalBytesRead < _fileSize)
    {
        ReadFromDownloadStream();
    }
    else
    {
        // Finished downloading
    }
}

我已经尝试过同时写入/读取MemoryStream,如上所列,以及写入IsolatedStorageFile并在写入时从该文件读取。到目前为止,我无法找到一种方法来使这两种方法都有效。

问题:

有没有办法读取和写入相同的流?或者是否有一种标准的方法来实现流和MediaStreamSource?

由于

1 个答案:

答案 0 :(得分:1)

我在MediaStreamSource实现中的方式是在其中包含2个流:一个用于读取,一个用于写入。

每次调用GetSampleAsync()时,我都会使用写入流的缓冲区来处理和重新创建读取流。另一种方法我猜测是在创建MediaStreamSample时使用负偏移量传递给ReportGetSampleCompleted(),因为流的位置总是在最后,但你必须确保位置在最后这是行不通的,为了保持简单,我只使用了2个流