// %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));
}
}
}