Воспроизведение больших файлов в проигрывателе Windows Media во время загрузки

Мой вопрос касается записи видеофайла на жесткий диск, который загружается из сети, и одновременного его воспроизведения с помощью Windows Media Player. Файл довольно большой, и его загрузка займет некоторое время. Это необходимо для загрузки, а не для потоковой передачи напрямую в проигрыватель Windows Media.

Что происходит, хотя я могу записывать в видеофайл и одновременно читать его из моего собственного тестового кода, этого нельзя сделать с помощью Windows Media Player (по крайней мере, я не понял этого). Я знаю, что это возможно, потому что это делают загрузки Amazon Unbox. Unbox позволяет воспроизводить файлы WMV во время их загрузки. А Unbox написан на .NET, так что ...

Я прочитал «чтение / запись файла C # не делает» Кажется, работает "вопрос и ответы на открытие файла с помощью флажков FileShare. Но у меня это не работает. Process Monitor сообщает, что Media Player открывает файл с флагами Fileshare, но выдает ошибку.

В потоке буферизации у меня есть этот код для чтения файла из сети и записи его в файл (без обработки ошибок или других вещей, чтобы сделать его более читаемым):

// the download thread
void StartStreaming(Stream webStream, int bufferFullByteCount)
{
    int bytesRead;
    var buffer = new byte[4096];
    var fileStream = new FileStream(MediaFile.FullName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
    var writer = new BinaryWriter(fileStream);
    var totalBytesRead = 0;
    do
    {
        bytesRead = webStream.Read(buffer, 0, 4096);
        if (bytesRead != 0)
        {
            writer.Write(buffer, 0, (int)bytesRead);
            writer.Flush();
            totalBytesRead += bytesRead;
        }
        if (totalBytesRead >= bufferFullByteCount)
        {
            // fire an event to a different thread to tell 
            // Windows Media Player to start playing
            OnBufferingComplete(this, new BufferingCompleteEventArgs(this, MediaFile));
        }
    } while (bytesRead != 0);
}

Кажется, это нормально работает. Файл записывается на диск и имеет правильные разрешения.

Но затем в другом потоке есть обработчик событий для воспроизведения видео.

    // the playback thread

private void OnBufferingComplete(object sender, BufferingCompleteEventArgs e)
{
    axWindowsMediaPlayer1.URL = e.MediaFile.FullName;
}

Проигрыватель Windows Media указывает, что он открывает файл, а затем просто останавливается с ошибкой, что файл не может быть открыт «уже открыт в другом процессе».

Я перепробовал все, что мог придумать. Что мне не хватает? Если парни из Amazon могут это сделать, то смогу и я, верно?

изменить: этот код работает с mplayer, VLC и Media Player Classic; только не проигрыватель Windows Media или проигрыватель Windows Media Center. IOW, единственные игроки, с которыми мне нужно работать. фу!

edit2: Я дошел до того, что использовал MiniHttp для потоковой передачи видео в Windows Media Player, чтобы посмотреть, может ли это «обмануть» WMP в воспроизведении загружаемого видео. Ничего не делая. Хотя WMP действительно открывал файл, он ждал, пока файл mpeg не будет полностью скопирован, прежде чем начать воспроизведение. Откуда это знать?

edit3: Покопавшись, я обнаружил проблему. Я работаю с файлами MPEG2. Проблема не обязательно в проигрывателе Windows Media, а в Microsoft MPEG2 DirectShow Splitter, который WMP использует для открытия файлов MPEG2, которые я пытаюсь воспроизвести и загрузить одновременно. Splitter открывает файлы в режиме без общего доступа. Не так с файлами WMV. WMP открывает их в общем режиме, и все работает как положено.


person CLaRGe    schedule 15.03.2009    source источник


Ответы (3)


Я решил ответить на свой вопрос на случай, если кто-то еще столкнется с этой редкой ситуацией.

Краткий ответ таков: Windows Media Player (на момент написания этой статьи) позволяет загружать и воспроизводить файл одновременно, если эта функция поддерживается кодеками, участвующими в рендеринге файла.

Процитируем последнее изменение вопроса:

Покопавшись, я обнаружил проблему. Я работаю с файлами MPEG2. Проблема не обязательно в проигрывателе Windows Media, а в Microsoft MPEG2 DirectShow Splitter, который WMP использует для открытия файлов MPEG2, которые я пытаюсь воспроизвести и загрузить одновременно. Splitter открывает файлы в режиме без общего доступа. Не так с файлами WMV. WMP открывает их в общем режиме, и все работает как положено.

person CLaRGe    schedule 01.04.2009

Когда вы открываете файл для записи, вы не должны использовать FileShare.ReadWrite. Вместо этого вы должны использовать FileShare.Read:

var fileStream = new FileStream(
    MediaFile.FullName, FileMode.Create, FileAccess.Write, FileShare.Read);

Когда процесс mplayer.exe откроет файл для чтения, он сначала попытается открыть его с помощью FileShare.Read, что не удастся, но затем будет повторная попытка с помощью FileShare.ReadWrite, которая завершится успешно.

person Darin Dimitrov    schedule 15.03.2009
comment
К сожалению, это работает для mplayer.exe, VLC и mplayerc.exe, но не для Windows Media Player. Хотел бы я знать, какой магией занимаются парни из Unbox. - person CLaRGe; 15.03.2009

Обновлено 16 марта после комментария @darin:

Вы указываете FileShare.ReadWrite при записи файла, что теоретически позволяет другому процессу открыть его для записи.

Попробуйте изменить свой код так, чтобы он запрашивал только FileShare.Read:

var fileStream 
    = new FileStream(
        MediaFile.FullName, 
        FileMode.Create, 
        FileAccess.Write, 
        FileShare.Read); // Instead of ReadWrite

Чтобы процитировать MSDN:

FileShare.Read: разрешает последующее открытие файла для чтения.

FileShare.ReadWrite: разрешает последующее открытие файла для чтения или записи.

person Bevan    schedule 15.03.2009
comment
@Bevan, указание FileShare.Write при создании файла означает, что медиаплеер никогда не сможет открыть файл для чтения. - person Darin Dimitrov; 15.03.2009
comment
@darin - спасибо за внимание. FileShare не означал того, что я думал. Я обновил свой ответ, чтобы он лучше понимал. - person Bevan; 16.03.2009