Я создаю 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
)?