// %BANNER_BEGIN% // --------------------------------------------------------------------- // %COPYRIGHT_BEGIN% // Copyright (c) (2018-2022) Magic Leap, Inc. All Rights Reserved. // Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2 // Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein. // %COPYRIGHT_END% // --------------------------------------------------------------------- // %BANNER_END% using System; using System.Runtime.InteropServices; using UnityEngine.XR.MagicLeap.Native; namespace UnityEngine.XR.MagicLeap { /// /// MLMedia APIs. /// public partial class MLMedia { /// /// APIs for MediaMuxer to facilitate muxing of elementary streams. /// public sealed partial class Muxer { /// /// Output formats for MediaMuxer.
/// Use to query for all supported output formats for the Muxer. ///
public enum OutputFormat { /// /// MP4 format /// MPEG4 = 0, /// /// VP8/VORBIS data in a WEBM container /// WEBM = 1, /// /// 3gpp format /// ThreeGPP = 2, /// /// HEIC data in a HEIF container /// HEIF = 3, /// /// Opus audio data in an OGG container /// OGG = 4 } /// /// Indicate the type of data when queuing the input buffer of muxer sample data /// [Flags] public enum CodecBufferFlags { /// /// The (encoded) buffer contains the data for a key frame. /// KeyFrame = 1, /// /// Signals the end of stream, i.e. no buffers will be available after this. /// EOS = 4, /// /// Buffer contains muxer data - Supported only for Exif data block. /// MuxerData = 16 } private ulong handle = MagicLeapNativeBindings.InvalidHandle; public Muxer() { var result = NativeBindings.MLMediaMuxerCreate(out handle); MLResult.DidNativeCallSucceed(result, nameof(NativeBindings.MLMediaMuxerCreate)); } ~Muxer() { var result = NativeBindings.MLMediaMuxerRelease(handle); MLResult.DidNativeCallSucceed(result, nameof(NativeBindings.MLMediaMuxerRelease)); } /// /// Configure the for a given output format with output path. /// /// The format of the muxed output media file. Value should be one returned from /// /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult Configure(OutputFormat format, string filePath) { var resultCode = NativeBindings.MLMediaMuxerConfigure(handle, (int)format, filePath); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaMuxerConfigure)); return MLResult.Create(resultCode); } /// /// Start muxing. Make sure all the tracks have been added ( or ) before calling this.
/// If the Muxer has already been Stopped, it cannot be re-Started. ///
/// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult Start() { var resultCode = NativeBindings.MLMediaMuxerStart(handle); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaMuxerStart)); return MLResult.Create(resultCode); } /// /// Stop muxing. Once the muxer Stops, it can not be re-Started. /// /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult Stop() { var resultCode = NativeBindings.MLMediaMuxerStop(handle); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaMuxerStop)); return MLResult.Create(resultCode); } /// /// Get a list of all the supported Media Muxer Output Formats. /// /// Array of that will contain the supported formats. /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult GetSupportedOutputFormats(out OutputFormat[] results) => MLResult.Create(InternalGetSupportedOutputFormats(out results)); /// /// Get a list of all the supported mime-types for a given Media Muxer Output Format. /// /// for which to retrieve supported MIME types. /// Array that will contain the supported MIME type names. /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult GetSupportedMimes(OutputFormat format, out string[] results) => MLResult.Create(InternalGetSupportedMimeTypes(format, out results)); /// /// Add a new audio track. This should be called before and after .

/// can be used to query for all the supported MIME types for a given audio output format. ///
/// The audio content's MIME type. /// The audio's sample rate. /// The number of audio channels. /// Index of the added audio track. /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult AddAudioTrack(string mimeType, int sampleRate, int channels, out int addedTrackIndex) { MLMediaFormat mediaFormat = MLMediaFormat.CreateAudio(mimeType, sampleRate, channels); addedTrackIndex = -1; return (mediaFormat != null) ? MLResult.Create(InternalAddTrack(mediaFormat.Handle, out addedTrackIndex)) : MLResult.Create(MLResult.Code.UnspecifiedFailure); } /// /// Add a new video track. This should be called before and after .

/// can be used to query for all the supported MIME types for a given video output format. ///
/// The video content's MIME type. /// The video content's width in pixels. /// The video content's height in pixels. /// Index of the added video track. /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult AddVideoTrack(string mimeType, int width, int height, out int addedTrackIndex) { MLMediaFormat mediaFormat = MLMediaFormat.CreateVideo(mimeType, width, height); addedTrackIndex = -1; return (mediaFormat != null) ? MLResult.Create(InternalAddTrack(mediaFormat.Handle, out addedTrackIndex)) : MLResult.Create(MLResult.Code.UnspecifiedFailure); } /// /// Set the orientation hint for output video playback.

/// This should be called before and after

/// Calling this method will not rotate the video frame when muxer is generating the file, /// but add a composition matrix containing the rotation angle in the output video /// if the output format is so that a video player can choose /// the proper orientation for playback.

/// Note that some video players may choose to ignore the composition matrix /// in a video during playback. By default, the rotation degree is 0. ///
/// The rotation angle. Must be 0, 90, 180 or 270. /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult SetOrientationHint(int degrees) { var resultCode = NativeBindings.MLMediaMuxerSetOrientationHint(handle, degrees); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaMuxerSetOrientationHint)); return MLResult.Create(resultCode); } /// /// Set and store the geodata (latitude and longitude) in the output file.

/// This should be called before and after .
/// The geodata is stored in udta box if the output format is ,
/// and is ignored for other output formats.

/// The geodata is stored according to ISO-6709 standard. ///
/// The latitude in degrees. Its value must be in the range [-90, 90]. /// The longitude in degrees. Its value must be in the range [-180, 180]. /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult SetLocation(float latitude, float longitude) { var resultCode = NativeBindings.MLMediaMuxerSetLocation(handle, latitude, longitude); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaMuxerSetLocation)); return MLResult.Create(resultCode); } /// /// Writes an encoded sample into the muxer.

/// The application needs to make sure that the samples are written into the right tracks.
/// Also, it needs to make sure the samples for each track are written in chronological order
/// (e.g. in the order they are provided by the encoder.)
///
/// The track index number to write the sample data into. This should be one of the number returned by and /// Buffer of data to write to the muxer /// Timestamp in microseconds /// MLMediaCodecBufferFlag. Supported values: KeyFrame, EOS, and MuxerData /// with Code "Ok" if the operation completed successfully without errors. Check for status. public MLResult WriteSampleData(int trackIndex, byte[] data, long time, CodecBufferFlags flags) => MLResult.Create(InternalWriteSampleData(trackIndex, data, time, flags)); } } }