Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makalede, medya dosyalarına veya akışlara eklenmiş olabilecek çeşitli zamanlanmış meta veri biçimlerinden nasıl yararlanılacağı açıklanmaktadır. UWP uygulamaları, meta veri işaretçileriyle her karşılaşıldığında oynatma sırasında medya işlem hattı tarafından oluşturulan etkinliklere kaydolabilir. DataCue sınıfını kullanarak uygulamalar kendi özel meta veri ipuçlarını uygulayabilir, ancak bu makalede medya işlem hattı tarafından otomatik olarak algılanan çeşitli meta veri standartlarına odaklanılır, örneğin:
- VobSub biçiminde görüntü tabanlı alt yazılar
- Konuşma ipuçları, sözcük sınırları, cümle sınırları ve Konuşma Sentezi Biçimlendirme Dili (SSML) yer işaretleri dahil.
- Bölüm ipuçları
- Genişletilmiş M3U açıklamaları
- ID3 etiketleri
- Parçalanmış mp4 emsg kutuları
Bu makale MediaSource, MediaPlaybackItem ve TimedMetadataTrack sınıfları ile çalışmanın temellerini ve uygulamanızda zamanlanmış meta verileri kullanmaya yönelik genel yönergeleri içeren Medya öğeleri, çalma listeleri ve parçalar makalesinde ele alınan kavramları temel alır.
Temel uygulama adımları, bu makalede açıklanan farklı zamanlanmış meta veri türleri için aynıdır:
- Yürütülecek içerik için bir MediaSource ve ardından bir MediaPlaybackItem oluşturun.
- Medya öğesinin alt parçaları medya işlem hattı tarafından çözümlendikçe gerçekleşen MediaPlaybackItem.TimedMetadataTracksChanged olayına kaydolun.
- Kullanmak istediğiniz zamanlanmış meta veri parçaları için TimedMetadataTrack.CueEntered ve TimedMetadataTrack.CueExited olaylarına kaydolun.
- CueEntered olay işleyicisinde, olay birleştirmelerinde geçirilen meta verileri temel alarak kullanıcı arabiriminizi güncelleştirin. Kullanıcı arabirimini yeniden güncelleştirerek geçerli alt başlık metnini (örneğin CueExited olayında) kaldırabilirsiniz.
Bu makalede, her meta veri türünün işlenmesi ayrı bir senaryo olarak gösterilir, ancak çoğunlukla paylaşılan kodu kullanarak farklı meta veri türlerini işlemek (veya yoksaymak) mümkündür. TimedMetadataTrack nesnesinin TimedMetadataKind özelliğini işlemin birden çok noktasında de kontrol edebilirsiniz. Bu nedenle, örneğin TimedMetadataKind.ImageSubtitle değerine sahip meta veri parçaları için CueEntered olayına kaydolmayı seçebilirsiniz, ancak TimedMetadataKind.Speech değerine sahip parçalar için kaydolmayı seçemeyebilirsiniz. Bunun yerine, tüm meta veri izleme türleri için bir işleyici kaydedebilir ve ardından CueEntered işleyicisinin içindeki TimedMetadataKind değerini denetledikten sonra ipucuna yanıt olarak hangi eylemin gerçekleştirileceğini belirleyebilirsiniz.
Görüntü tabanlı alt yazılar
Windows 10, sürüm 1703'den itibaren UWP uygulamaları VobSub biçiminde dış görüntü tabanlı alt yazıları destekleyebilir. Bu özelliği kullanmak için, önce resim alt yazılarının görüntüleneceği medya içeriği için bir MediaSource nesnesi oluşturun. Ardından, createFromUriWithIndex veya CreateFromStreamWithIndex çağrısı yaparak, alt başlık resim verilerini içeren .sub dosyasının Uri'sini ve alt yazıların zamanlama bilgilerini içeren .idx dosyasını geçirerek bir TimedTextSource nesnesi oluşturun. TimedTextSource'ı kaynağın ExternalTimedTextSources koleksiyonuna ekleyerek MediaSource'a ekleyin. MediaSource'tan bir MediaPlaybackItem oluşturun.
var contentUri = new Uri("http://contoso.com/content.mp4");
var mediaSource = MediaSource.CreateFromUri(contentUri);
var subUri = new Uri("http://contoso.com/content.sub");
var idxUri = new Uri("http://contoso.com/content.idx");
var timedTextSource = TimedTextSource.CreateFromUriWithIndex(subUri, idxUri);
mediaSource.ExternalTimedTextSources.Add(timedTextSource);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
Önceki adımda oluşturulan MediaPlaybackItem nesnesini kullanarak resim alt başlığı meta veri olaylarına kaydolun. Bu örnekte, olaylara kaydolmak için RegisterMetadataHandlerForImageSubtitles adlı bir yardımcı yöntemi kullanılır. Bir lambda ifadesi, sistem MediaPlaybackItem ile ilişkili meta veri parçalarında bir değişiklik algıladığında oluşan TimedMetadataTracksChanged olayı için bir işleyici uygulamak için kullanılır. Bazı durumlarda, çalma öğesi ilk çözümlendiğinde meta veri parçalarının kullanılabilir olması mümkündür; bu nedenle TimedMetadataTracksChanged işleyicisinin dışında, kullanılabilir meta veri parçaları arasında döngü oluştururuz ve RegisterMetadataHandlerForImageSubtitles'ı çağırırız.
mediaPlaybackItem.TimedMetadataTracksChanged += (MediaPlaybackItem sender, IVectorChangedEventArgs args) =>
{
if (args.CollectionChange == CollectionChange.ItemInserted)
{
RegisterMetadataHandlerForImageSubtitles(sender, (int)args.Index);
}
else if (args.CollectionChange == CollectionChange.Reset)
{
for (int index = 0; index < sender.TimedMetadataTracks.Count; index++)
{
if (sender.TimedMetadataTracks[index].TimedMetadataKind == TimedMetadataKind.ImageSubtitle)
RegisterMetadataHandlerForImageSubtitles(sender, index);
}
}
};
for (int index = 0; index < mediaPlaybackItem.TimedMetadataTracks.Count; index++)
{
RegisterMetadataHandlerForImageSubtitles(mediaPlaybackItem, index);
}
Görüntü alt başlığı meta veri olaylarına kaydettikten sonra MediaItem, bir MediaPlayer’a atanır ve MediaPlayerElement içinde çalıştırılır.
_mediaPlayer = new MediaPlayer();
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
_mediaPlayer.Source = mediaPlaybackItem;
_mediaPlayer.Play();
RegisterMetadataHandlerForImageSubtitles yardımcı yönteminde, MediaPlaybackItem'inTimedMetadataTracks koleksiyonuna dizin ekleyerek TimedMetadataTrack sınıfının bir örneğini alın. CueEntered olayına ve CueExited olayına kaydolun. Ardından, uygulamaya bu kayıttan yürütme öğesi için meta veri ipucu olaylarını almak istediğini bildirmek için kayıttan yürütme öğesinin TimedMetadataTracks koleksiyonunda SetPresentationMode öğesini çağırmanız gerekir.
private void RegisterMetadataHandlerForImageSubtitles(MediaPlaybackItem item, int index)
{
var timedTrack = item.TimedMetadataTracks[index];
timedTrack.CueEntered += metadata_ImageSubtitleCueEntered;
timedTrack.CueExited += metadata_ImageSubtitleCueExited;
item.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
}
CueEntered olayının işleyicisinde, meta verilerin resim alt yazıları için olup olmadığını görmek için işleyiciye geçirilen TimedMetadataTrack nesnesinin TimedMetadataKind özelliğini de kontrol edebilirsiniz. Birden çok meta veri türü için aynı veri ipucu olay işleyicisini kullanıyorsanız bu gereklidir. İlişkili meta veri izi TimedMetadataKind.ImageSubtitle türündeyse, MediaCueEventArgs'ın Cue özelliğinde bulunan veri ipucunu bir ImageCue olarak dönüştürün. ImageCue'nunSoftwareBitmap özelliği, alt başlık görüntüsünün SoftwareBitmap gösterimini içerir. Bir SoftwareBitmapSource oluşturun ve görüntüyü bir XAML Görüntü denetimine atamak için SetBitmapAsync'i çağırın. ImageCue'nunKapsam ve Konum özellikleri, alt yazı görüntüsünün boyutu ve konumu hakkında bilgi sağlar.
private async void metadata_ImageSubtitleCueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
{
// Check in case there are different tracks and the handler was used for more tracks
if (timedMetadataTrack.TimedMetadataKind == TimedMetadataKind.ImageSubtitle)
{
var cue = args.Cue as ImageCue;
if (cue != null)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(cue.SoftwareBitmap);
SubtitleImage.Source = source;
SubtitleImage.Width = cue.Extent.Width;
SubtitleImage.Height = cue.Extent.Height;
SubtitleImage.SetValue(Canvas.LeftProperty, cue.Position.X);
SubtitleImage.SetValue(Canvas.TopProperty, cue.Position.Y);
});
}
}
}
Konuşma ipuçları
Windows 10, sürüm 1703'ten itibaren UWP uygulamaları, medya oynatılırken sözcük sınırlarına, cümle sınırlarına ve Konuşma Sentezi Biçimlendirme Dili (SSML) yer işaretlerine yanıt olarak etkinlikleri almak için kaydolabilir. Bu, SpeechSynthesizer sınıfıyla oluşturulan ses akışlarını yürütmenize ve şu anda yürütülmekte olan sözcüğün veya cümlenin metnini görüntüleme gibi bu olaylara göre kullanıcı arabiriminizi güncelleştirmenize olanak tanır.
Bu bölümde gösterilen örnek, sentezlenecek ve oynatılacak bir metin dizesini depolamak için sınıf üyesi değişkenini kullanır.
string inputText = "In the lake heading for the mountain, the flea swims";
SpeechSynthesizer sınıfının yeni bir örneğini oluşturun. Meta verilerin oluşturulan medya akışına eklenmesi gerektiğini belirtmek üzere birleştirici için IncludeWordBoundaryMetadata ve IncludeSentenceBoundaryMetadata seçeneklerini true olarak ayarlayın. Sentezlenmiş konuşmayı ve karşılık gelen meta verileri içeren bir akış oluşturmak için SynthesizeTextToStreamAsync'i çağırın. Sentezlenmiş akıştan bir MediaSource ve MediaPlaybackItem oluşturun.
var synthesizer = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
// Enable word marker generation (false by default).
synthesizer.Options.IncludeWordBoundaryMetadata = true;
synthesizer.Options.IncludeSentenceBoundaryMetadata = true;
var stream = await synthesizer.SynthesizeTextToStreamAsync(inputText);
var mediaSource = MediaSource.CreateFromStream(stream, "");
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
MediaPlaybackItem nesnesini kullanarak konuşma meta verileri olaylarına kaydolun. Bu örnekte olaylara kaydolmak için RegisterMetadataHandlerForSpeech yardımcı yöntemi kullanılır. Bir lambda ifadesi, sistem MediaPlaybackItem ile ilişkili meta veri parçalarında bir değişiklik algıladığında oluşan TimedMetadataTracksChanged olayı için bir işleyici uygulamak için kullanılır. Bazı durumlarda, oynatma öğesi ilk çözümlendiğinde meta veri parçaları mevcut olabilir; bu durumda, TimedMetadataTracksChanged işleyicisinin dışında mevcut olan meta veri parçaları üzerinde dönerek RegisterMetadataHandlerForSpeech'i çağırırız.
// Since the tracks are added later we will
// monitor the tracks being added and subscribe to the ones of interest
mediaPlaybackItem.TimedMetadataTracksChanged += (MediaPlaybackItem sender, IVectorChangedEventArgs args) =>
{
if (args.CollectionChange == CollectionChange.ItemInserted)
{
RegisterMetadataHandlerForSpeech(sender, (int)args.Index);
}
else if (args.CollectionChange == CollectionChange.Reset)
{
for (int index = 0; index < sender.TimedMetadataTracks.Count; index++)
{
RegisterMetadataHandlerForSpeech(sender, index);
}
}
};
// If tracks were available at source resolution time, itterate through and register:
for (int index = 0; index < mediaPlaybackItem.TimedMetadataTracks.Count; index++)
{
RegisterMetadataHandlerForSpeech(mediaPlaybackItem, index);
}
Konuşma meta verileri olaylarına kaydolan MediaItem , MediaPlayerElement içinde kayıttan yürütme için bir MediaPlayer'a atanır.
_mediaPlayer = new MediaPlayer();
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
_mediaPlayer.Source = mediaPlaybackItem;
_mediaPlayer.Play();
RegisterMetadataHandlerForSpeech yardımcı yönteminde, MediaPlaybackItem'inTimedMetadataTracks koleksiyonuna dizin ekleyerek TimedMetadataTrack sınıfının bir örneğini alın. CueEntered olayına ve CueExited olayına kaydolun. Ardından, uygulamaya bu kayıttan yürütme öğesi için meta veri ipucu olaylarını almak istediğini bildirmek için kayıttan yürütme öğesinin TimedMetadataTracks koleksiyonunda SetPresentationMode öğesini çağırmanız gerekir.
private void RegisterMetadataHandlerForSpeech(MediaPlaybackItem item, int index)
{
var timedTrack = item.TimedMetadataTracks[index];
timedTrack.CueEntered += metadata_SpeechCueEntered;
timedTrack.CueExited += metadata_SpeechCueExited;
item.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
}
CueEntered olayının işleyicisinde, meta verilerin konuşma olup olmadığını görmek için işleyiciye geçirilen TimedMetadataTrack nesnesinin TimedMetadataKind özelliğini de kontrol edebilirsiniz. Birden çok meta veri türü için aynı veri ipucu olay işleyicisini kullanıyorsanız bu gereklidir. İlişkili meta veri parçası TimedMetadataKind.Speech türündeyse, MediaCueEventArgs'ın Cue özelliğinde bulunan veri ipucunu SpeechCue'ya dönüştürün. Konuşma ipuçları için, meta veri izlemesine dahil edilen konuşma ipucunun türü Label özelliği denetlenerek belirlenir. Bu özelliğin değeri sözcük sınırları için "SpeechWord", cümle sınırları için "SpeechSentence" veya SSML yer işaretleri için "SpeechBookmark" olacaktır. Bu örnekte "SpeechWord" değerini denetleriz ve bu değer bulunursa, SpeechCue'nunStartPositionInput ve EndPositionInput özellikleri, yürütülmekte olan sözcüğün giriş metni içindeki konumu belirlemek için kullanılır. Bu örnek, her sözcüğü hata ayıklama çıktısına basitçe gönderir.
private void metadata_SpeechCueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
{
// Check in case there are different tracks and the handler was used for more tracks
if (timedMetadataTrack.TimedMetadataKind == TimedMetadataKind.Speech)
{
var cue = args.Cue as SpeechCue;
if (cue != null)
{
if (timedMetadataTrack.Label == "SpeechWord")
{
// Do something with the cue
System.Diagnostics.Debug.WriteLine($"{cue.StartPositionInInput} - {cue.EndPositionInInput}: {inputText.Substring((int)cue.StartPositionInInput, ((int)cue.EndPositionInInput - (int)cue.StartPositionInInput) + 1)}");
}
}
}
}
Bölüm ipuçları
Windows 10, sürüm 1703'den itibaren UWP uygulamaları, bir medya öğesi içindeki bölümlere karşılık gelen ipuçlarına kaydolabilir. Bu özelliği kullanmak için, medya içeriği için bir MediaSource nesnesi oluşturun ve ardından MediaSource'tan bir MediaPlaybackItem oluşturun.
var contentUri = new Uri("http://contoso.com/content.mp4");
var mediaSource = MediaSource.CreateFromUri(contentUri);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
Önceki adımda oluşturulan MediaPlaybackItem nesnesini kullanarak bölüm meta verileri olaylarına kaydolun. Bu örnekte olaylara kaydolmak için RegisterMetadataHandlerForChapterCues adlı bir yardımcı yöntem kullanılır. Bir lambda ifadesi, sistem MediaPlaybackItem ile ilişkili meta veri parçalarında bir değişiklik algıladığında oluşan TimedMetadataTracksChanged olayı için bir işleyici uygulamak için kullanılır. Bazı durumlarda, kayıttan yürütme öğesi ilk çözümlendiğinde meta veri parçaları kullanılabilir, bu nedenle TimedMetadataTracksChanged işleyicisi dışında, kullanılabilir meta veri parçaları arasında döngü oluşturur ve RegisterMetadataHandlerForChapterCues'u çağırırız.
mediaPlaybackItem.TimedMetadataTracksChanged += (MediaPlaybackItem sender, IVectorChangedEventArgs args) =>
{
if (args.CollectionChange == CollectionChange.ItemInserted)
{
RegisterMetadataHandlerForChapterCues(sender, (int)args.Index);
}
else if (args.CollectionChange == CollectionChange.Reset)
{
for (int index = 0; index < sender.TimedMetadataTracks.Count; index++)
{
if (sender.TimedMetadataTracks[index].TimedMetadataKind == TimedMetadataKind.ImageSubtitle)
RegisterMetadataHandlerForChapterCues(sender, index);
}
}
};
for (int index = 0; index < mediaPlaybackItem.TimedMetadataTracks.Count; index++)
{
RegisterMetadataHandlerForChapterCues(mediaPlaybackItem, index);
}
Bölüm meta verileri olaylarına kaydolan MediaItem, MediaPlayer içinde kayıttan yürütme için bir MediaPlayerElement'e atanır.
_mediaPlayer = new MediaPlayer();
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
_mediaPlayer.Source = mediaPlaybackItem;
_mediaPlayer.Play();
RegisterMetadataHandlerForChapterCues yardımcı yönteminde, MediaPlaybackItem'inTimedMetadataTracks koleksiyonuna dizin ekleyerek TimedMetadataTrack sınıfının bir örneğini alın. CueEntered olayına ve CueExited olayına kaydolun. Ardından, uygulamaya bu kayıttan yürütme öğesi için meta veri ipucu olaylarını almak istediğini bildirmek için kayıttan yürütme öğesinin TimedMetadataTracks koleksiyonunda SetPresentationMode öğesini çağırmanız gerekir.
private void RegisterMetadataHandlerForChapterCues(MediaPlaybackItem item, int index)
{
var timedTrack = item.TimedMetadataTracks[index];
timedTrack.CueEntered += metadata_ChapterCueEntered;
timedTrack.CueExited += metadata_ChapterCueExited;
item.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
}
CueEntered olayının işleyicisinde, meta verilerin bölüm ipuçları için olup olmadığını görmek için işleyiciye geçirilen TimedMetadataTrack nesnesinin TimedMetadataKind özelliğini de kontrol edebilirsiniz. Birden çok meta veri türü için aynı veri ipucu olay işleyicisini kullanıyorsanız bu gereklidir. İlişkili meta veri parçası TimedMetadataKind.Chapter türündeyse, MediaCueEventArgs'ın Cue özelliğinde bulunan veri göstergesini bir ChapterCue'ya çevirin. ChapterCue'unTitle özelliği, kayıttan yürütmede yeni ulaşılan bölümün başlığını içerir.
private async void metadata_ChapterCueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
{
// Check in case there are different tracks and the handler was used for more tracks
if (timedMetadataTrack.TimedMetadataKind == TimedMetadataKind.Chapter)
{
var cue = args.Cue as ChapterCue;
if (cue != null)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ChapterTitleTextBlock.Text = cue.Title;
});
}
}
}
Bölüm ipuçlarını kullanarak sonraki bölüme gitme
Geçerli bölüm bir yürütme öğesinde değiştiğinde bildirim almaya ek olarak, bir yürütme öğesi içinde sonraki bölümü aramak için bölüm ipuçlarını da kullanabilirsiniz. Aşağıda gösterilen örnek yöntem, o anda yürütülmekte olan medya öğesini temsil eden bir MediaPlayer ve bir MediaPlaybackItem bağımsız değişkenleri olarak alır. TimedMetadataTracks koleksiyonu, parçalardan herhangi birinde TimedMetadataKind özelliğinin TimedMetadataKind.Chapter değerinin TimedMetadataTrack değerine sahip olup olmadığını görmek için aranmaktadır. Eğer bir bölüm parçası bulunursa, yöntem, medya oynatıcının kayıttan yürütme oturumunun geçerli Konumundan daha büyük bir Başlangıç Zamanı olan ilk ipucunu bulmak için parçanın Cues koleksiyonundaki her bir ipucunda döngü yapar. Doğru ipucu bulunduktan sonra kayıttan yürütme oturumunun konumu güncelleştirilir ve bölüm başlığı kullanıcı arabiriminde güncelleştirilir.
private void GoToNextChapter(MediaPlayer player, MediaPlaybackItem item)
{
// Find the chapters track if one exists
TimedMetadataTrack chapterTrack = item.TimedMetadataTracks.FirstOrDefault(track => track.TimedMetadataKind == TimedMetadataKind.Chapter);
if (chapterTrack == null)
{
return;
}
// Find the first chapter that starts after current playback position
TimeSpan currentPosition = player.PlaybackSession.Position;
foreach (ChapterCue cue in chapterTrack.Cues)
{
if (cue.StartTime > currentPosition)
{
// Change player position to chapter start time
player.PlaybackSession.Position = cue.StartTime;
// Display chapter name
ChapterTitleTextBlock.Text = cue.Title;
break;
}
}
}
Genişletilmiş M3U açıklamaları
Windows 10, sürüm 1703'den itibaren UWP uygulamaları, Genişletilmiş M3U bildirim dosyasındaki açıklamalara karşılık gelen ipuçlarına kaydolabilir. Bu örnekte medya içeriğini yürütmek için AdaptiveMediaSource kullanılır. Daha fazla bilgi için bkz. Uyarlamalı Akış. CreateFromUriAsync veya CreateFromStreamAsync çağrısı yaparak içerik için AdaptiveMediaSource oluşturun. CreateFromAdaptiveMediaSource'u çağırarak bir MediaSource nesnesi oluşturun ve ardından MediaSource'tan bir MediaPlaybackItem oluşturun.
AdaptiveMediaSourceCreationResult result =
await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://contoso.com/playlist.m3u"));
if (result.Status != AdaptiveMediaSourceCreationStatus.Success)
{
// TODO: Handle adaptive media source creation errors.
return;
}
var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(result.MediaSource);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
Önceki adımda oluşturulan MediaPlaybackItem nesnesini kullanarak M3U meta veri olaylarına kaydolun. Bu örnekte, olaylara kaydolmak için RegisterMetadataHandlerForEXTM3UCues adlı bir yardımcı yöntemi kullanılır. Bir lambda ifadesi, sistem MediaPlaybackItem ile ilişkili meta veri parçalarında bir değişiklik algıladığında oluşan TimedMetadataTracksChanged olayı için bir işleyici uygulamak için kullanılır. Bazı durumlarda, kayıttan yürütme öğesi ilk çözümlendiğinde meta veri parçaları zaten kullanılabilir durumdadır. Bu nedenle, TimedMetadataTracksChanged işleyicisinin dışında, mevcut meta veri parçalarına da göz atar ve RegisterMetadataHandlerForEXTM3UCues'i çağırırız.
mediaPlaybackItem.TimedMetadataTracksChanged += (MediaPlaybackItem sender, IVectorChangedEventArgs args) =>
{
if (args.CollectionChange == CollectionChange.ItemInserted)
{
RegisterMetadataHandlerForEXTM3UCues(sender, (int)args.Index);
}
else if (args.CollectionChange == CollectionChange.Reset)
{
for (int index = 0; index < sender.TimedMetadataTracks.Count; index++)
{
if (sender.TimedMetadataTracks[index].TimedMetadataKind == TimedMetadataKind.ImageSubtitle)
RegisterMetadataHandlerForEXTM3UCues(sender, index);
}
}
};
for (int index = 0; index < mediaPlaybackItem.TimedMetadataTracks.Count; index++)
{
RegisterMetadataHandlerForEXTM3UCues(mediaPlaybackItem, index);
}
M3U meta veri olaylarına kaydolan MediaItem, MediaPlayerElement içinde kayıttan yürütme için bir MediaPlayer'a atanır.
_mediaPlayer = new MediaPlayer();
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
_mediaPlayer.Source = mediaPlaybackItem;
_mediaPlayer.Play();
RegisterMetadataHandlerForEXTM3UCues yardımcı yönteminde, MediaPlaybackItem'inTimedMetadataTracks koleksiyonuna dizin ekleyerek TimedMetadataTrack sınıfının bir örneğini alın. Parça M3U açıklamalarını temsil ediyorsa meta veri parçasının DispatchType özelliği "EXTM3U" değerine sahip olacaktır, bunu kontrol edin. CueEntered olayına ve CueExited olayına kaydolun. Ardından, uygulamaya bu kayıttan yürütme öğesi için meta veri ipucu olaylarını almak istediğini bildirmek için kayıttan yürütme öğesinin TimedMetadataTracks koleksiyonunda SetPresentationMode öğesini çağırmanız gerekir.
private void RegisterMetadataHandlerForEXTM3UCues(MediaPlaybackItem item, int index)
{
var timedTrack = item.TimedMetadataTracks[index];
var dispatchType = timedTrack.DispatchType;
if (String.Equals(dispatchType, "EXTM3U", StringComparison.OrdinalIgnoreCase))
{
timedTrack.Label = "EXTM3U comments";
timedTrack.CueEntered += metadata_EXTM3UCueEntered;
timedTrack.CueExited += metadata_EXTM3UCueExited;
item.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
}
}
CueEntered olayının işleyicisinde MediaCueEventArgs'ınCue özelliğinde bulunan veri ipucunu bir DataCue'a dönüştürebilirsiniz. İşaretin DataCue ve Data özelliğinin null olmadığından emin olun. Genişletilmiş EMU açıklamaları UTF-16, küçük uçlu, null ile sonlandırılmış dizeler biçiminde sağlanır. DataReader.FromBuffer'ı çağırarak ipucu verilerini okumak için yeni bir DataReader oluşturun. Verileri doğru biçimde okumak için okuyucunun UnicodeEncoding özelliğini Utf16LE olarak ayarlayın. Verileri okumak için ReadString'i çağırın; her karakter iki bayt boyutunda olduğundan Veri alanının uzunluğunun yarısını belirtin ve sonundaki null karakteri kaldırmak için birini çıkarın. Bu örnekte, M3U açıklaması yalnızca hata ayıklama çıkışına yazılır.
private void metadata_EXTM3UCueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
{
var dataCue = args.Cue as DataCue;
if (dataCue != null && dataCue.Data != null)
{
// The payload is a UTF-16 Little Endian null-terminated string.
// It is any comment line in a manifest that is not part of the HLS spec.
var dr = Windows.Storage.Streams.DataReader.FromBuffer(dataCue.Data);
dr.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
var m3uComment = dr.ReadString(dataCue.Data.Length / 2 - 1);
System.Diagnostics.Debug.WriteLine(m3uComment);
}
}
ID3 etiketleri
Windows 10, sürüm 1703'den itibaren UWP uygulamaları, Http Canlı Akış (HLS) içeriğindeki ID3 etiketlerine karşılık gelen ipuçlarına kaydolabilir. Bu örnekte medya içeriğini yürütmek için AdaptiveMediaSource kullanılır. Daha fazla bilgi için bkz. Uyarlamalı Akış. CreateFromUriAsync veya CreateFromStreamAsync çağrısı yaparak içerik için AdaptiveMediaSource oluşturun. CreateFromAdaptiveMediaSource'u çağırarak bir MediaSource nesnesi oluşturun ve ardından MediaSource'tan bir MediaPlaybackItem oluşturun.
AdaptiveMediaSourceCreationResult result =
await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://contoso.com/playlist.m3u"));
if (result.Status != AdaptiveMediaSourceCreationStatus.Success)
{
// TODO: Handle adaptive media source creation errors.
return;
}
var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(result.MediaSource);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
Önceki adımda oluşturulan MediaPlaybackItem nesnesini kullanarak ID3 etiket olaylarına kaydolun. Bu örnekte olaylara kaydolmak için RegisterMetadataHandlerForID3Cues yardımcı yöntemi kullanılır. Bir lambda ifadesi, sistem MediaPlaybackItem ile ilişkili meta veri parçalarında bir değişiklik algıladığında oluşan TimedMetadataTracksChanged olayı için bir işleyici uygulamak için kullanılır. Bazı durumlarda, oynatma öğesi ilk çözümlendiğinde meta veri parçaları mevcut olabilir, bu nedenle TimedMetadataTracksChanged işleyicisinin dışında mevcut meta veri parçaları üzerinde döngü oluşturur ve RegisterMetadataHandlerForID3Cues'u çağırırız.
AdaptiveMediaSourceCreationResult result =
await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://contoso.com/playlist.m3u"));
if (result.Status != AdaptiveMediaSourceCreationStatus.Success)
{
// TODO: Handle adaptive media source creation errors.
return;
}
var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(result.MediaSource);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
ID3 meta veri olaylarına kaydolduktan sonra, MediaItem bir MediaPlayer içinde, MediaPlayerElement ile kayıttan yürütme için atanır.
_mediaPlayer = new MediaPlayer();
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
_mediaPlayer.Source = mediaPlaybackItem;
_mediaPlayer.Play();
RegisterMetadataHandlerForID3Cues yardımcı yönteminde, MediaPlaybackItem'inTimedMetadataTracks koleksiyonuna dizin ekleyerek TimedMetadataTrack sınıfının bir örneğini alın. Meta veri parçasının DispatchType özelliğini kontrol edin; eğer parça ID3 etiketlerini temsil ediyorsa, "15260DFFFF49443320FF49443320000F" GUID dizesini içeren bir değere sahip olacaktır. CueEntered olayına ve CueExited olayına kaydolun. Ardından, uygulamaya bu kayıttan yürütme öğesi için meta veri ipucu olaylarını almak istediğini bildirmek için kayıttan yürütme öğesinin TimedMetadataTracks koleksiyonunda SetPresentationMode öğesini çağırmanız gerekir.
private void RegisterMetadataHandlerForID3Cues(MediaPlaybackItem item, int index)
{
var timedTrack = item.TimedMetadataTracks[index];
var dispatchType = timedTrack.DispatchType;
if (String.Equals(dispatchType, "15260DFFFF49443320FF49443320000F", StringComparison.OrdinalIgnoreCase))
{
timedTrack.Label = "ID3 tags";
timedTrack.CueEntered += metadata_ID3CueEntered;
timedTrack.CueExited += metadata_ID3CueExited;
item.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
}
}
CueEntered olayının işleyicisinde MediaCueEventArgs'ınCue özelliğinde bulunan veri ipucunu bir DataCue'a dönüştürebilirsiniz. İşaretin DataCue ve Data özelliğinin null olmadığından emin olun. Genişletilmiş EMU açıklamaları aktarım akışındaki ham bayt biçiminde sağlanır (bkz . ID3). DataReader.FromBuffer'ı çağırarak ipucu verilerini okumak için yeni bir DataReader oluşturun. Bu örnekte, ID3 etiketindeki üst bilgi değerleri işaret verilerinden okunur ve hata ayıklama çıkışına yazılır.
private void metadata_ID3CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
{
var dataCue = args.Cue as DataCue;
if (dataCue != null && dataCue.Data != null)
{
// The payload is the raw ID3 bytes found in a TS stream
// Ref: http://id3.org/id3v2.4.0-structure
var dr = Windows.Storage.Streams.DataReader.FromBuffer(dataCue.Data);
var header_ID3 = dr.ReadString(3);
var header_version_major = dr.ReadByte();
var header_version_minor = dr.ReadByte();
var header_flags = dr.ReadByte();
var header_tagSize = dr.ReadUInt32();
System.Diagnostics.Debug.WriteLine($"ID3 tag data: major {header_version_major}, minor: {header_version_minor}");
}
}
Parçalanmış mp4 emsg kutuları
Windows 10, sürüm 1703'den itibaren UWP uygulamaları parçalanmış mp4 akışları içindeki emsg kutularına karşılık gelen ipuçlarına kaydolabilir. Bu tür meta verilerin örnek bir kullanımı, içerik sağlayıcılarının canlı akış içeriği sırasında bir reklamı oynatmaları için istemci uygulamalarına sinyal göndermeleridir. Bu örnekte medya içeriğini yürütmek için AdaptiveMediaSource kullanılır. Daha fazla bilgi için bkz. Uyarlamalı Akış. CreateFromUriAsync veya CreateFromStreamAsync çağrısı yaparak içerik için AdaptiveMediaSource oluşturun. CreateFromAdaptiveMediaSource'u çağırarak bir MediaSource nesnesi oluşturun ve ardından MediaSource'tan bir MediaPlaybackItem oluşturun.
AdaptiveMediaSourceCreationResult result =
await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://contoso.com/playlist.m3u"));
if (result.Status != AdaptiveMediaSourceCreationStatus.Success)
{
// TODO: Handle adaptive media source creation errors.
return;
}
var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(result.MediaSource);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
Önceki adımda oluşturulan MediaPlaybackItem nesnesini kullanarak emsg kutusu olaylarına kaydolun. Bu örnekte, olaylara kaydolmak için RegisterMetadataHandlerForEmsgCues adlı bir yardımcı yöntemi kullanılır. Bir lambda ifadesi, sistem MediaPlaybackItem ile ilişkili meta veri parçalarında bir değişiklik algıladığında oluşan TimedMetadataTracksChanged olayı için bir işleyici uygulamak için kullanılır. Bazı durumlarda, çalma öğesi ilk çözümlendiğinde meta veri parçaları kullanılabilir, bu nedenle TimedMetadataTracksChanged işleyicisine ek olarak, mevcut meta veri parçaları arasında döngüyle geçeriz ve RegisterMetadataHandlerForEmsgCues'u çağırırız.
AdaptiveMediaSourceCreationResult result =
await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://contoso.com/playlist.m3u"));
if (result.Status != AdaptiveMediaSourceCreationStatus.Success)
{
// TODO: Handle adaptive media source creation errors.
return;
}
var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(result.MediaSource);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
Emsg kutusu meta veri olaylarına kaydolan MediaItem, MediaPlayerElement içinde kayıttan yürütme için bir MediaPlayer'a atanır.
_mediaPlayer = new MediaPlayer();
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
_mediaPlayer.Source = mediaPlaybackItem;
_mediaPlayer.Play();
RegisterMetadataHandlerForEmsgCues yardımcı yönteminde, MediaPlaybackItem'inTimedMetadataTracks koleksiyonuna dizin ekleyerek TimedMetadataTrack sınıfının bir örneğini alın. Meta veri izinin DispatchType özelliğini kontrol edin; bu özellik, iz emsg kutularını temsil ediyorsa "emsg:mp4" değerine sahip olur. CueEntered olayına ve CueExited olayına kaydolun. Ardından, uygulamaya bu kayıttan yürütme öğesi için meta veri ipucu olaylarını almak istediğini bildirmek için kayıttan yürütme öğesinin TimedMetadataTracks koleksiyonunda SetPresentationMode öğesini çağırmanız gerekir.
private void RegisterMetadataHandlerForEmsgCues(MediaPlaybackItem item, int index)
{
var timedTrack = item.TimedMetadataTracks[index];
var dispatchType = timedTrack.DispatchType;
if (String.Equals(dispatchType, "emsg:mp4", StringComparison.OrdinalIgnoreCase))
{
timedTrack.Label = "mp4 Emsg boxes";
timedTrack.CueEntered += metadata_EmsgCueEntered;
timedTrack.CueExited += metadata_EmsgCueExited;
item.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
}
}
CueEntered olayının işleyicisinde MediaCueEventArgs'ınCue özelliğinde bulunan veri ipucunu bir DataCue'a dönüştürebilirsiniz. DataCue nesnesinin null olmadığından emin olun. Emsg kutusunun özellikleri, medya işlem hattı tarafından DataCue nesnesinin Properties koleksiyonunda özel özellikler olarak sağlanır. Bu örnek , TryGetValue yöntemini kullanarak birkaç farklı özellik değerini ayıklamayı dener. Bu yöntem null döndürürse, istenen özelliğin emsg kutusunda mevcut olmadığı anlamına gelir, bu nedenle bunun yerine varsayılan bir değer ayarlanır.
Örneğin sonraki bölümü, önceki adımda elde edilen scheme_id_uri özelliğinin "urn:scte:scte35:2013:xml" değerine sahip olmasının, reklam oynatımının tetiklendiği senaryoyu gösterdiği durumu açıklamaktadır. Daha fazla bilgi için bkz. https://dashif.org/identifiers/event_schemes/. Standart, bu emsg'nin yedeklilik için birden çok kez gönderilmesini önerdiğini, bu nedenle bu örnekte zaten işlenmiş olan ve yalnızca yeni iletileri işleyen emsg kimliklerinin listesinin tutulduğunu unutmayın. DataReader.FromBuffer'ı çağırarak ipucu verilerini okumak için yeni bir DataReader oluşturun ve UnicodeEncoding özelliğini ayarlayarak kodlamayı UTF-8 olarak ayarlayın ve ardından verileri okuyun. Bu örnekte, ileti yükü hata ayıklama çıkışına yazılır. Gerçek bir uygulama, bir reklamın yayınlanmasını zamanlamak için yük verilerini kullanır.
private void metadata_EmsgCueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
{
var dataCue = args.Cue as DataCue;
if (dataCue != null)
{
string scheme_id_uri = string.Empty;
string value = string.Empty;
UInt32 timescale = (UInt32)TimeSpan.TicksPerSecond;
UInt32 presentation_time_delta = (UInt32)dataCue.StartTime.Ticks;
UInt32 event_duration = (UInt32)dataCue.Duration.Ticks;
UInt32 id = 0;
Byte[] message_data = null;
const string scheme_id_uri_key = "emsg:scheme_id_uri";
object propValue = null;
dataCue.Properties.TryGetValue(scheme_id_uri_key, out propValue);
scheme_id_uri = propValue != null ? (string)propValue : "";
const string value_key = "emsg:value";
propValue = null;
dataCue.Properties.TryGetValue(value_key, out propValue);
value = propValue != null ? (string)propValue : "";
const string timescale_key = "emsg:timescale";
propValue = null;
dataCue.Properties.TryGetValue(timescale_key, out propValue);
timescale = propValue != null ? (UInt32)propValue : timescale;
const string presentation_time_delta_key = "emsg:presentation_time_delta";
propValue = null;
dataCue.Properties.TryGetValue(presentation_time_delta_key, out propValue);
presentation_time_delta = propValue != null ? (UInt32)propValue : presentation_time_delta;
const string event_duration_key = "emsg:event_duration";
propValue = null;
dataCue.Properties.TryGetValue(event_duration_key, out propValue);
event_duration = propValue != null ? (UInt32)propValue : event_duration;
const string id_key = "emsg:id";
propValue = null;
dataCue.Properties.TryGetValue(id_key, out propValue);
id = propValue != null ? (UInt32)propValue : 0;
System.Diagnostics.Debug.WriteLine($"Label: {timedMetadataTrack.Label}, Id: {dataCue.Id}, StartTime: {dataCue.StartTime}, Duration: {dataCue.Duration}");
System.Diagnostics.Debug.WriteLine($"scheme_id_uri: {scheme_id_uri}, value: {value}, timescale: {timescale}, presentation_time_delta: {presentation_time_delta}, event_duration: {event_duration}, id: {id}");
if (dataCue.Data != null)
{
var dr = Windows.Storage.Streams.DataReader.FromBuffer(dataCue.Data);
// Check if this is a SCTE ad message:
// Ref: http://dashif.org/identifiers/event-schemes/
if (scheme_id_uri.ToLower() == "urn:scte:scte35:2013:xml")
{
// SCTE recommends publishing emsg more than once, so we avoid reprocessing the same message id:
if (!processedAdIds.Contains(id))
{
processedAdIds.Add(id);
dr.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
var scte35payload = dr.ReadString(dataCue.Data.Length);
System.Diagnostics.Debug.WriteLine($", message_data: {scte35payload}");
// TODO: ScheduleAdFromScte35Payload(timedMetadataTrack, presentation_time_delta, timescale, event_duration, scte35payload);
}
else
{
System.Diagnostics.Debug.WriteLine($"This emsg.Id, {id}, has already been processed.");
}
}
else
{
message_data = new byte[dataCue.Data.Length];
dr.ReadBytes(message_data);
// TODO: Use the 'emsg' bytes for something useful.
System.Diagnostics.Debug.WriteLine($", message_data.Length: {message_data.Length}");
}
}
}
}
İlgili konular