Xamarin lowering video size

2019-07-29 11:26发布

问题:

i want to "compress" videos (for upload) in Xamarin (iOS). I found out about the AVAssetWriter Class and i red that you could set the resolution, bitrate etc. How would you use it? Which other classes? As you may already noticed, im very new to app development.

回答1:

Here is a sample using AVAssetReader to feed AVAssetWriter to re-sample and/or transcode a video.

In this example, I am taking a video named "Pool.mp4" that was included in app bundle (BundleResource) and saving into the "tmp" directory as "NewVideo.mp4" at a size of 300x300 at 1Mbps (reducing the original file size by ~50%...)

Note: No return values or error codes are being checked, that is left up to the implementor.

var asset = AVAsset.FromUrl(NSUrl.FromFilename("Pool.mp4"));
NSError assetReaderError;
var assetReader = AVAssetReader.FromAsset(asset, out assetReaderError);
var assetTrack = asset.Tracks.First();
var inputSettings = new AVVideoSettingsUncompressed() 
{
    Height = 300,
    Width = 300,
};
var assetReaderOutput = new AVAssetReaderTrackOutput(assetTrack, settings: inputSettings);
assetReaderOutput.AlwaysCopiesSampleData = false;

string tempFile = Path.Combine(Path.GetTempPath(), "NewVideo.mp4");
if (File.Exists(tempFile)) File.Delete(tempFile);
var url = NSUrl.FromFilename(tempFile);
NSError assetWriterError;
var assetWriter = new AVAssetWriter(url, AVFileType.Mpeg4, out assetWriterError);
var outputSettings = new AVVideoSettingsCompressed()
{
    Height = 300,
    Width = 300,
    Codec = AVVideoCodec.H264,
    CodecSettings = new AVVideoCodecSettings
    {
        AverageBitRate = 1000000
    }
};
var assetWriterInput = new AVAssetWriterInput(mediaType: AVMediaType.Video, outputSettings: outputSettings);
assetWriterInput.ExpectsMediaDataInRealTime = false;
assetWriter.AddInput(assetWriterInput);

assetWriter.StartWriting();
assetReader.AddOutput(assetReaderOutput);
assetReader.StartReading();
assetWriter.StartSessionAtSourceTime(CoreMedia.CMTime.Zero);

var mediaInputQueue = new DispatchQueue("mediaInputQueue");
assetWriterInput.RequestMediaData(mediaInputQueue, () =>
{
    while (assetWriterInput.ReadyForMoreMediaData)
    {
        var nextBuffer = assetReaderOutput.CopyNextSampleBuffer();
        if (nextBuffer != null)
        {
            assetWriterInput.AppendSampleBuffer(nextBuffer);
        }
        else
        {
            assetWriterInput.MarkAsFinished();
            assetWriter.FinishWritingAsync();
            assetReader.CancelReading();
            assetReader.Dispose();
            assetReaderOutput.Dispose();
            assetWriter.Dispose();
            assetWriterInput.Dispose();
            break;
        }
    }
});