Skip to content

Commit a1f72a4

Browse files
committed
Resolve content type identification on macios
1 parent b86fbb7 commit a1f72a4

2 files changed

Lines changed: 44 additions & 12 deletions

File tree

src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,17 @@ protected virtual async partial ValueTask PlatformUpdateSource()
274274
{
275275
// Create a custom URL scheme for the stream
276276
var streamUrl = new NSUrl("stream://media");
277-
277+
278278
// Create an AVURLAsset with the custom scheme
279279
var urlAsset = new AVUrlAsset(streamUrl);
280-
280+
281281
// Create and set up the resource loader
282282
streamResourceLoader?.Dispose();
283283
streamResourceLoader = new StreamAssetResourceLoader(streamMediaSource.Stream, GetStreamContentType(streamMediaSource.Stream));
284-
284+
285285
// Assign the resource loader delegate
286286
urlAsset.ResourceLoader.SetDelegate(streamResourceLoader, DispatchQueue.MainQueue);
287-
287+
288288
asset = urlAsset;
289289
}
290290
}
@@ -491,12 +491,44 @@ protected virtual void Dispose(bool disposing)
491491

492492
static string GetStreamContentType(Stream stream)
493493
{
494-
// Default to a generic media type
495-
// In a more sophisticated implementation, you could:
496-
// 1. Read magic bytes from the stream to detect type
497-
// 2. Accept content type as a parameter on StreamMediaSource
498-
// 3. Use file extension if available
499-
return "video/mp4"; // Default assumption
494+
// Try to detect content type from magic bytes
495+
if (stream.CanSeek && stream.Length > 12)
496+
{
497+
var originalPosition = stream.Position;
498+
try
499+
{
500+
stream.Position = 0;
501+
var buffer = new byte[12];
502+
var bytesRead = stream.Read(buffer, 0, 12);
503+
504+
if (bytesRead >= 12)
505+
{
506+
// Check for MP4/M4V/MOV signature (ftyp box at offset 4)
507+
if (buffer[4] == 0x66 && buffer[5] == 0x74 && buffer[6] == 0x79 && buffer[7] == 0x70)
508+
{
509+
// Check specific brand
510+
var brand = System.Text.Encoding.ASCII.GetString(buffer, 8, 4);
511+
512+
// Most iOS videos will be either mp4, m4v, or qt (QuickTime)
513+
// For AVFoundation, we should use UTI: "public.mpeg-4" or "com.apple.quicktime-movie"
514+
if (brand.StartsWith("qt", StringComparison.Ordinal))
515+
{
516+
return "com.apple.quicktime-movie";
517+
}
518+
519+
return "public.mpeg-4";
520+
}
521+
}
522+
}
523+
finally
524+
{
525+
stream.Position = originalPosition;
526+
}
527+
}
528+
529+
// Default to MPEG-4 (MP4) - covers most cases
530+
// Using UTI format for iOS/macOS
531+
return "public.mpeg-4";
500532
}
501533

502534
static TimeSpan ConvertTime(CMTime cmTime) => TimeSpan.FromSeconds(double.IsNaN(cmTime.Seconds) ? 0 : cmTime.Seconds);
@@ -763,4 +795,4 @@ void RateChanged(object? sender, NSNotificationEventArgs args)
763795
}
764796
}
765797
}
766-
}
798+
}

src/CommunityToolkit.Maui.MediaElement/Views/StreamAssetResourceLoader.macios.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ sealed class StreamAssetResourceLoader : AVAssetResourceLoaderDelegate
1111
readonly Stream stream;
1212
readonly string contentType;
1313

14-
public StreamAssetResourceLoader(Stream stream, string contentType = "application/octet-stream")
14+
public StreamAssetResourceLoader(Stream stream, string contentType = "public.mpeg-4")
1515
{
1616
ArgumentNullException.ThrowIfNull(stream);
1717
this.stream = stream;

0 commit comments

Comments
 (0)