Xamarin - 如何设置/更改 VideoView 显示预览方向

Posted

技术标签:

【中文标题】Xamarin - 如何设置/更改 VideoView 显示预览方向【英文标题】:Xamarin - How to set/change VideoView display preview orientation 【发布时间】:2017-06-07 09:45:03 【问题描述】:

我从https://developer.xamarin.com/recipes/android/media/video/record_video/ 复制了一个代码,这是关于制作视频流的说明,我正在尝试更改其中的某些部分。

我已经尝试使用 SetOrientationHint(90) 将输出方向更改为 90

但由于此代码不使用 Camera 类,而仅使用 MediaRecorder 类。我如何旋转显示预览,因为它给了我一个 +90 度和横向预览?

我已经在 xml 和代码中尝试过旋转,但是预览变成了全黑。

这是代码

[Activity(Label = "App2", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity, ISurfaceHolderCallback

    string path = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/test.mp4";
    MediaRecorder recorder;

    protected override void OnCreate(Bundle bundle)
    
        base.OnCreate(bundle);
        //Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);
        var record = FindViewById<Button>(Resource.Id.Record);
        var stop = FindViewById<Button>(Resource.Id.Stop);
        var play = FindViewById<Button>(Resource.Id.Play);
        var video = FindViewById<VideoView>(Resource.Id.SampleVideoView);
        //video.Rotation = 90;

        record.Click += delegate
        
            if (recorder == null)
                recorder = startRecording(video);
            else
                Toast.MakeText(this, "Now recording", 0).Show();
        ;

        stop.Click += delegate
        
            if (recorder != null)
            
                stopRecording(recorder);
                recorder = null;
            
            else
                Toast.MakeText(this, "No video recording", 0).Show();
        ;

        play.Click += delegate
        
            if (path != null)
                playVideo(video);
            else
                Toast.MakeText(this, "No video available", 0).Show();
        ;

        //recorder = startRecording(video);
    

    protected override void OnDestroy()
    
        base.OnDestroy();

        if (recorder != null)
        
            recorder.Release();
            recorder.Dispose();
            recorder = null;
        
    

    private void playVideo(VideoView video)
    
        var uri = Android.Net.Uri.Parse(path);
        video.SetVideoURI(uri);
        video.Start();
    

    private static void stopRecording(MediaRecorder recorder)
    
        if (recorder != null)
        
            recorder.Stop();
            recorder.Release();
        
    

    private MediaRecorder startRecording(VideoView video)
    
        MediaRecorder recorder;
        video.StopPlayback();

        //video.Holder.AddCallback(this);
        //video.Holder.SetType(SurfaceType.PushBuffers);

        recorder = new MediaRecorder();
        recorder.SetVideoSource(VideoSource.Camera);
        recorder.SetAudiosource(AudioSource.Mic);
        recorder.SetOutputFormat(OutputFormat.Default);
        recorder.SetVideoEncoder(VideoEncoder.Default);
        recorder.SetAudioEncoder(AudioEncoder.Default);
        recorder.SetOutputFile(path);
        recorder.SetOrientationHint(90);
        recorder.SetPreviewDisplay(video.Holder.Surface);
        if (recorder!=null)
        
            try
            
                recorder.Prepare();
                recorder.Start();
            
            catch (Exception)
            
                Toast.MakeText(this, "Exception!", 0).Show();
            
        
        return recorder;
    

    public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
    
        throw new NotImplementedException();
    

    public void SurfaceCreated(ISurfaceHolder holder)
    
        throw new NotImplementedException();
    

    public void SurfaceDestroyed(ISurfaceHolder holder)
    
        throw new NotImplementedException();
    

更新

@Elvis Xia 的回答很有帮助。 这是新代码

[Activity(Label = "App2", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity, ISurfaceHolderCallback

    string path = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/test.mp4";
    MediaRecorder recorder;
    Android.Hardware.Camera mCamera; //Android.Hardware is used because it will have 
                                     //problem with Android.Graphics

    protected override void OnCreate(Bundle bundle)
    
        base.OnCreate(bundle);
        //Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);
        var record = FindViewById<Button>(Resource.Id.Record);
        var stop = FindViewById<Button>(Resource.Id.Stop);
        var play = FindViewById<Button>(Resource.Id.Play);
        var video = FindViewById<VideoView>(Resource.Id.SampleVideoView);

        record.Click += delegate
        
            if (recorder == null)
                recorder = startRecording(video);
            else
                Toast.MakeText(this, "Now recording", 0).Show();
        ;

        stop.Click += delegate
        
            if (recorder != null)
            
                stopRecording(recorder, mCamera);
                recorder = null;
            
            else
                Toast.MakeText(this, "No video recording", 0).Show();
        ;

        play.Click += delegate
        
            if (path != null)
                playVideo(video);
            else
                Toast.MakeText(this, "No video available", 0).Show();
        ;

        //recorder = startRecording(video);
    

    protected override void OnDestroy()
    
        base.OnDestroy();

        if (recorder != null)
        
            recorder.Release();
            recorder.Dispose();
            recorder = null;
        
    

    private void playVideo(VideoView video)
    
        var uri = Android.Net.Uri.Parse(path);
        video.SetVideoURI(uri);
        video.Start();
    

    private static void stopRecording(MediaRecorder recorder, Android.Hardware.Camera mCamera)
    
        if (recorder != null)
        
            recorder.Stop();
            recorder.Release();
            mCamera.StopPreview();
            mCamera.Release();
        
    

    private MediaRecorder startRecording(VideoView video)
    
        MediaRecorder recorder;
        video.StopPlayback();

        //video.Holder.AddCallback(this);
        //video.Holder.SetType(SurfaceType.PushBuffers);

        recorder = new MediaRecorder();
        mCamera = GetCameraInstance();
        mCamera.SetDisplayOrientation(90);
        mCamera.Unlock();
        recorder.SetCamera(mCamera);
        recorder.SetVideoSource(VideoSource.Camera);
        recorder.SetAudioSource(AudioSource.Mic);
        recorder.SetOutputFormat(OutputFormat.Default);
        recorder.SetVideoEncoder(VideoEncoder.Default);
        recorder.SetAudioEncoder(AudioEncoder.Default);
        recorder.SetOutputFile(path);
        recorder.SetOrientationHint(90);
        recorder.SetPreviewDisplay(video.Holder.Surface);
        if (recorder!=null)
        
            try
            
                recorder.Prepare();
                recorder.Start();
            
            catch (Exception)
            
                Toast.MakeText(this, "Exception!", 0).Show();
            
        
        return recorder;
    

    public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
    
        throw new NotImplementedException();
    

    public void SurfaceCreated(ISurfaceHolder holder)
    
        throw new NotImplementedException();
    

    public void SurfaceDestroyed(ISurfaceHolder holder)
    
        throw new NotImplementedException();
    

    public static Android.Hardware.Camera GetCameraInstance()
    
        Android.Hardware.Camera c = null;
        try
        
            c = Android.Hardware.Camera.Open();
        
        catch (Exception e)
        

        
        return c;
    

【问题讨论】:

【参考方案1】:

但由于此代码不使用 Camera 类,而仅使用 MediaRecorder 类。我如何旋转显示预览,因为它给了我一个 +90 度和横向预览?

设置旋转度数后需要将CameraMediaRecorder关联:

    通过GetCameraInstace获取相机实例:

    public static Camera GetCameraInstance()
    
        Camera c = null;
        try
        
            c = Camera.Open();
        
        catch (Exception e)
        
    
        
        return c;
    
    

    MainActivity.cs记录按钮点击事件中,将cameraMediaRecorder关联,并在mCamera.Unlock之前设置方向:

    Camera mCamera
    ...
    
    recorder = new MediaRecorder();
    mCamera = ClassName.GetCameraInstance(); //ClassName if in different class. 
                                             //else just GetCameraInstance();
    mCamera.SetDisplayOrientation(90);
    mCamera.Unlock();
    recorder.SetCamera(mCamera);
    
    recorder.SetVideoSource(VideoSource.Camera);
    

【讨论】:

那台相机是来自 Android.Hardware 类的吗? . Utility.GetCameraInstance() 中的实用程序是什么?这是你的班级名字吗? 是的。 Camera 来自 Android.HardwareUtility只是我用来封装GetCameraInstance静态方法的一个类。 我已经尝试过了,它解决了我的定位问题 :) 感谢您的帮助。对于其他人:也不要忘记停止预览并释放相机。

以上是关于Xamarin - 如何设置/更改 VideoView 显示预览方向的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.iOS - 如何动态更改标签字体大小?

如何使用 Xamarin Forms 更改键盘的习惯用法

如何更改 Xamarin.Forms UWP 应用程序的强调色?

如何检测 xamarin UWP 应用程序中标签元素的文本值更改?

我将如何设置 Xamarin Forms Android Picker 弹出窗口的背景颜色

Xamarin Form - 如何在 UWP 中为 MyToolkit.Controls.DataGrid 设置样式