【发布时间】:2020-01-17 19:19:45
【问题描述】:
我正在构建一个 C# .NET Core 应用程序,它收集用户交互数据并将其与视频源一起存储。我打算利用 MPEG 容器中的定时元数据来存储交互数据和 h264 编码的视频数据。
According to the official documentation 似乎可以在使用MediaTranscoder 进行转码操作期间对元数据流进行编码。
我使用的代码已从screen recorder example 修改。它的工作原理是创建一个自定义MediaEncodingProfile 设置以支持元数据和一个包含VideoStreamDescriptor 和TimedMetadataStreamDescriptor 的MediaStreamSource,然后再使用它们执行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)时,在编码期间向流中添加仅基于每个样本可用的定时元数据的正确方法是什么?
【问题讨论】:
-
您好,能否提供一个最小可重现的demo和应用所需的系统版本?我们已经注意到您的问题,正在联系工程师寻求帮助。
-
抱歉耽搁了。 download here 有一个完整的示例。如果您构建并运行该示例,调试器将中断事件处理程序方法,该方法仅被调用以请求视频样本而不是元数据样本。此示例在 .NET Core 3.1.1 和 Windows 10 1909 18363.592 上运行,但我们在版本 1903 和 1809 上也遇到过此问题。感谢您的帮助。
-
@RichardZhang-MSFT 这是什么状态?有没有人可以直接联系来解决这个问题?
-
您好,我已报告您提供的样本存在此问题。如果有新的进展,我会第一时间发在这里。
标签: c# windows .net-core uwp transcoding