Кодирование метаданных Timed с MediaStreamSource и MediaTranscoder - PullRequest
0 голосов
/ 17 января 2020

Я создаю C#. NET Базовое приложение, которое собирает данные о взаимодействии с пользователем и сохраняет их вместе с видеопотоком. Я намерен использовать синхронизированные метаданные в контейнере MPEG для хранения данных взаимодействия и видеоданных в кодировке h264.

Согласно официальной документации представляется возможным кодировать поток метаданных во время операция транскодирования с MediaTranscoder. Код, который я использую, был изменен из примера записи с экрана . Он работает путем создания пользовательского MediaEncodingProfile, настроенного для поддержки метаданных, и MediaStreamSource, содержащего как VideoStreamDescriptor, так и TimedMetadataStreamDescriptor, прежде чем использовать их для выполнения кодирования с MediaTranscoder.

public class Encoder
{
    private MediaEncodingProfile GetEncodingProfile()
    {
        var profile = new MediaEncodingProfile();
        var containerEncoding = new ContainerEncodingProperties
        {
            Subtype = MediaEncodingSubtypes.Mpeg4
        };

        var videoEncoding = new VideoEncodingProperties
        {
            Subtype = MediaEncodingSubtypes.H264,
            Width = configuration.Width,
            Height = configuration.Height,
            Bitrate = configuration.BitsPerSecond,
            FrameRate = { Denominator = 1, Numerator = configuration.FramesPerSecond },
            PixelAspectRatio = { Denominator = 1, Numerator = 1 }
        };

        profile.Container = containerEncoding;
        profile.Video = videoEncoding;

        return profile;
    }

    private Tuple<VideoStreamDescriptor, TimedMetadataStreamDescriptor> GetStreamDescriptors()
    {
        var videoEncoding = VideoEncodingProperties.CreateUncompressed(MediaEncodingSubtypes.Bgra8,
                                                                       configuration.InputWidth, configuration.InputHeight);

        var videoStreamDescriptor = new VideoStreamDescriptor(videoEncoding);

        var metadataEncoding = new TimedMetadataEncodingProperties
        {
            Subtype = "{36002D6F-4D0D-4FD7-8538-5680DA4ED58D}"
        };

        byte[] streamFormatData = GetMetadataStreamFormatData(); // This just sets some arbitrary bytes

        metadataEncoding.SetFormatUserData(streamFormatData);

        var metadataStreamDescriptor = new TimedMetadataStreamDescriptor(metadataEncoding);

        return new Tuple<VideoStreamDescriptor, TimedMetadataStreamDescriptor>(
                videoStreamDescriptor, metadataStreamDescriptor);
   }

   private MediaStreamSource GetMediaStreamSource(IMediaStreamDescriptor videoStreamDescriptor,
                                                  IMediaStreamDescriptor metadataStreamDescriptor)
   {
        var mediaStreamSource = new MediaStreamSource(videoStreamDescriptor, metadataStreamDescriptor)
        {
            BufferTime = TimeSpan.FromSeconds(0)
        };

        mediaStreamSource.Starting += OnStart;
        mediaStreamSource.SampleRequested += OnSampleRequested;

        return mediaStreamSource;
    }

    private void OnStart(MediaStreamSource sender, MediaStreamSourceStartingEventArgs args)
    {
        // Intentionally omitted
    }

    private void OnSampleRequested(MediaStreamSource sender, MediaStreamSourceSampleRequestedEventArgs args)
    {
        // This only gets called for the video stream, not the metadata stream
    }

    private MediaTranscoder GetTranscoder()
    {
        var transcoder = new MediaTranscoder { HardwareAccelerationEnabled = true };
        return transcoder;
    }

    public async Task TranscodeAsync()
    {
        var transcoder = GetTranscoder();

        var (videoStreamDescriptor, metadataStreamDescriptor) = GetStreamDescriptors();

        var mediaStreamSource = GetMediaStreamSource(videoStreamDescriptor, metadataStreamDescriptor);
        var encodingProfile = GetEncodingProfile();
        await using var destinationFile = File.Open(configuration.FilePath, FileMode.Create);

        var prepareTranscodeResult = await transcoder.PrepareMediaStreamSourceTranscodeAsync(
                    mediaStreamSource, destinationFile.AsRandomAccessStream(), encodingProfile);
        await prepareTranscodeResult.TranscodeAsync().AsTask();
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что событие SampleRequested не вызывается для потока метаданных по времени, а только для видеопотока. Во время тестирования я заменил поток метаданных по времени на аудиопоток, и событие SampleRequested было правильно вызвано как для видеопотока, так и для аудиопотока. Я подозреваю, что может быть другой способ добавления данных в поток метаданных по времени, возможно, с использованием TimedMetadataTrack и DataCue, но мои усилия до сих пор оказались безуспешными.

Какой правильный способ добавления синхронизированных метаданные доступны только для каждой выборки при кодировании в поток при использовании MediaTranscoder (и, возможно, MediaStreamSource)?

1 Ответ

0 голосов
/ 04 марта 2020

После общения с инженером, теперь эта проблема имеет результат.

Хотя MediaTranscoder поддерживает синхронизированные потоки метаданных, когда профиль настроен в MF Transform Engine, он отбрасывается только для поддержки 1 аудио и 1 видео поток. Таким образом, использование MediaTranscoder никогда не будет работать.

Соответствующие документы были обновлены: Перекодируйте медиа-файлы

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...