旋转 Android VideoView

2024-03-27

我的应用程序仅提供纵向模式。在纵向活动中,我有一个全屏视频视图。我想要做的是在横向模式下将 VideoView(实际视频、视频缓冲区)旋转 90 度。无法让 Activity 处于横向模式。 扩展 VideoView 和画布旋转将不起作用,因为它是 SurfaceView 而不是实际视图。 有没有办法用 videoView 来实现这一点?


即使正确设置了合成矩阵并使用了旋转属性,VideoView 也不支持视频旋转。

您可以做的是使用TextureView并设置其属性rotation =“90”(例如)。然后它会旋转框架,但宽高比是您需要自行处理的。为此,您可以使用textureView.setScaleX((screenHeight * 1.0f) / screenWidth)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextureView
        android:id="@+id/playback_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:rotation="90" />
</RelativeLayout>

它也应该处理流视频。但请将其视为示例,而不是发布现成的代码。我重命名了一些内容并删除了其他内容,它们与问题无关,这可能会破坏某些内容,但总的来说这是可行的示例。

public class PlaybackActivity extends Activity implements MediaPlayer.OnErrorListener, OnPreparedListener,
        OnCompletionListener, OnVideoSizeChangedListener, OnBufferingUpdateListener, OnInfoListener,
        SurfaceTextureListener
{

    private MediaPlayer mediaPlayer;
    private TextureView videoView;
    private boolean startedPlayback = false;
    private boolean playerReady = false;
    public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703;

    private void createMediaPlayer() {
        mediaPlayer = new MediaPlayer();
    }

    private void releaseMediaPlayer() {
        if (mediaPlayer != null) {
            mediaPlayer.setSurface(null);
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    public void onCompletion(MediaPlayer mp) {
        Log.w(TAG, "Video playback finished");
    }

    @Override
    public boolean onError(MediaPlayer player, int what, int extra) {
        if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN) {
            /*
             * Restart play back in case we did not start anything yet. This may
             * be the case when we tried to tune in in very first secs of the
             * broadcast when there is no data yet.
             */
            if (liveBroadcast && mediaPlayer != null && !mediaPlayer.isPlaying() && !startedPlayback) {
                if (checkCount-- > 0) {
                    mediaPlayer.reset();
                    checkBroadcast();
                } else {
                    Log.w(TAG, "Broadcast finished");
                }
            } else {
                Log.w(TAG, "No media in stream");
            }
        } else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
            Log.w(TAG, "Media service died unexpectedly");
        } else {
            Log.w(TAG, "Unknown media error");
        }
        return true;
    }

   @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        switch (what) {
        case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
            Log.w(TAG, "Media is too complex to decode it fast enough.");
            startedPlayback = true;
            break;
        case MEDIA_INFO_NETWORK_BANDWIDTH:
            Log.w(TAG, "Bandwith in recent past.");
            break;
        case MediaPlayer.MEDIA_INFO_BUFFERING_START:
            Log.w(TAG, "Start of media bufferring.");
            startedPlayback = true;
            break;
        case MediaPlayer.MEDIA_INFO_BUFFERING_END:
            Log.w(TAG, "End of media bufferring.");
            startedPlayback = true;
            break;
        case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
            Log.w(TAG, "Media is not properly interleaved.");
            break;
        case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
            Log.w(TAG, "Stream is not seekable.");
            break;
        case MediaPlayer.MEDIA_INFO_METADATA_UPDATE:
            Log.w(TAG, "New set of metadata is available.");
            break;
        case MediaPlayer.MEDIA_INFO_UNKNOWN:
        default:
            Log.w(TAG, "Unknown playback info (" + what + ":" + extra + ").");
            break;
        }
        return true;
    }

    private void startPlayback() {
        if (mediaPlayer != null) {
            onLoaded(mediaPlayer);
            mediaPlayer.start();
        }
    }

    private void pausePlayback() {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
            mediaPlayer.pause();
    }

    private void resumePlayback() {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
            mediaPlayer.start();
    }

    private void onLoaded(MediaPlayer mp) {
    }

    public void onPrepared(MediaPlayer mp) {
        playerReady = true;
        startPlayback();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.playback);
        videoView = (TextureView) findViewById(R.id.playback_video);
        videoView.setOnClickListener(videoViewClickHandler);
        videoView.setSurfaceTextureListener(this);
        createMediaPlayer();
    }

   @Override
    protected void onDestroy() {
        releaseMediaPlayer();
        if (surface != null) {
            surface.release();
            surface = null;
        }
        super.onDestroy();
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        this.surface = new Surface(surface);
        loadMedia(someurl);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        if (this.surface != null) {
            releaseMediaPlayer();
            this.surface.release();
            this.surface = null;
        }
        return true;
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
    }

    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int w, int h) {
        if (w > 0 && h > 0 && !videoSizeSetupDone) {
            Log.w(TAG, "Video size changed: " + w + "x" + h);
            changeVideoSize(w, h);
        }
    }

    private boolean videoSizeSetupDone = false;

    private void changeVideoSize(int width, int height) {
        DisplayMetrics metrics = new DisplayMetrics();
        RelativeLayout.LayoutParams params;

        Utils.getScreenMetrics(this, metrics);
        VideoOrientation orientation = someVideoSource.getVideoOrientation();
        if (orientation == LANDSCAPE) {
            params = new RelativeLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels);
        } else {
            float rotation = orientation == BroadcastVideoOrientation.BroadcastVideoFrontCamera ? -90.0f : 90.0f;
            params = new RelativeLayout.LayoutParams(metrics.heightPixels, metrics.widthPixels);
            float scale = (width * 1.0f) / (height * 1.0f);
            videoView.setRotation(rotation);
            videoView.setScaleX(scale);
        }
        params.addRule(RelativeLayout.CENTER_IN_PARENT, -1);
        videoView.setLayoutParams(params);
        videoSizeSetupDone = true;
    }

    private void loadMedia(String url) {
        if (surface == null)
            return;
        Log.d(App.TAG, "Loading url: " + url);

        startedPlayback = false;
        try {
            mediaPlayer.reset();
            mediaPlayer.setSurface(surface);
            mediaPlayer.setDataSource(url);
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.setOnCompletionListener(this);
            mediaPlayer.setOnErrorListener(this);
            mediaPlayer.setOnVideoSizeChangedListener(this);
            mediaPlayer.setScreenOnWhilePlaying(true);
            mediaPlayer.setOnBufferingUpdateListener(this);
            mediaPlayer.setOnInfoListener(this);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            Log.w(TAG, "Media load failed");
            Utils.alert(this, "Playback Error", e.getMessage(), finishHandler);
        }
    }
}

希望这可以帮助。我寻找这个解决方案已经很长时间了。几乎尝试了所有方法,这似乎是唯一的方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

旋转 Android VideoView 的相关文章

  • Android 两次请求 USB 许可

    我有一个运行 Android 4 0 4 的开发板 并将其用作 USB 配件 当我关闭板上的应用程序然后通过 USB 插入 Android 手机时 板会提示 连接此 USB 设备时打开 AppName 当我触摸 确定 时 应用程序启动并再次
  • 如何获取 Android 应用程序的内部版本号?

    我需要弄清楚如何获取或创建我的 Android 应用程序的内部版本号 我需要在用户界面中显示内部版本号 我必须做点什么吗AndroidManifest xml 如果您使用 Gradle 插件 Android Studio 从版本 0 7 0
  • Firebase FCM 通知图像不会显示

    我在我的项目中使用 FCM 当尝试使用 firebase 撰写通知 功能测试传入通知时 我将标题 正文和图像 URL 添加到消息中 它显示了它应该是什么样子 丰富的通知与图像 但发送给我的通知是正常的 没有任何图像 这是 firebase
  • 安卓多点触控?

    作为一名开发人员 我倾向于先编程 然后再研究 我试图实现一个可以处理多个用户输入的屏幕 基本上映射的不仅仅是一根手指 我尝试了两件事 我有一个实现 OnTouchListener 的 Activity 类 这里我有两个单独的子视图 它们将
  • Android 在 ROOM 数据库中插入大量数据

    我有大约 10 个模型 每个模型都有超过 120K 行和 90 列的记录 其中包含双数组值 在 Room 中插入任何模型都需要超过 125 130 秒 任何人都可以建议我需要做什么才能使用一些批量插入技术来保存所有这些 120K 该技术大约
  • 在操作栏中编辑文本

    我正在使用 Action Bar Sherlock 为我的应用程序创建 UI 在将依赖项添加到我的项目等后 我创建了一个活动来测试它 public class PPS extends SherlockActivity Override pu
  • 如何更改所有 ListView 的默认分隔线颜色

    我正在尝试为 style xml 中的所有 listView 应用默认样式 请注意 在某些地方我使用嵌套列表视图 In 样式 xml
  • ListView 中的焦点控件

    上下文 我想要一个不会获得焦点的 ListView 例如不会 当用户触摸它时突出显示该行 然而每个行小部件都有它自己的 OnClickListener 这是我在布局 xml 中指定的内容 android choiceMode none an
  • 带操作栏的 requestFeature

    所以我正在查看 google 的操作栏 api 演示 他们有这个 The Action Bar is a window feature The feature must be requested before setting a conte
  • 如何通过代码改变Android SlidingDrawer的方向?

    当我从横向模式更改为纵向模式时 我无法找到设置 SlidingDrawer 方向的方法 反之亦然 最初我将 xml 的方向设置为垂直 当手机处于横向模式时 我需要将方向更改为水平 因此我将手柄放在左侧 有人有什么想法吗 我认为按照标准这是不
  • 如何使用GDK在卡片上显示静态地图?

    在 Mirror API 中我们可以使用类似的东西 img src height 360 width 240
  • 如何在 Android 上禁用 HTML 输入中的自动更正?

    我无法在 Android 上的网络浏览器中禁用文本输入的自动更正 我试过这个
  • Google 的新地点库(实现“com.google.android.libraries.places:1.0.0”)无法解析

    我正在尝试迁移到新的 Places SDK 客户端 但我被告知要安装的依赖项文档 https developers google com places android sdk client migration给我一个 无法解决 错误 我确保
  • android tabwidget意图选项卡刷新每次点击

    我想使用具有意图的子选项卡创建一个选项卡 以便当用户单击选项卡意图时刷新 每次用户单击选项卡时 我想刷新并调用子意图选项卡的 oncreate 方法 public class Tabs3 extends TabActivity Overri
  • MediaPlayer.getDuration() 返回错误的持续时间

    媒体播放器的getDuration 方法为我提供了某些音频文件的错误值 我认为所有这些文件的共同特征是它们是使用 Audacity 或其他一些音频编辑工具进行操作的 当尝试将 MediaPlayer 进度绑定到进度栏时 这是一个问题 我继续
  • 为什么 LayoutInflater 忽略我指定的layout_width 和layout_height 布局参数?

    我在让 LayoutInflater 按预期工作时遇到了严重的困难 其他人也是如此 如何使用layoutinflator在运行时添加视图 https stackoverflow com questions 4735847 help for
  • 为什么Android和IOS11无法通过NFC通信

    目前正在使用 React Native 并尝试使用反应本机 NFC ios https www npmjs com package react native nfc ios and 反应本机 NFC https github com Nov
  • 如何强制元数据值类型为字符串?

    我在manifest xml中指定了一个元数据 如下所示
  • Android Studio同时为同一个项目构建两个应用程序

    我正在使用 Android Studio v0 5 9 制作一个应用程序 它有一个图书馆项目作为依赖 但是 每次我运行该项目时 都会将两个具有相同名称和图标的 APK 部署到我的设备上 第一个 apk app 包含我的主模块 而第二个是库项
  • 找不到 com.google.gms:google-services:4.1.0 [重复]

    这个问题在这里已经有答案了 Bitrise 构建失败并出现以下错误 配置根项目 src 时出现问题 无法解析配置 classpath 的所有文件 找不到 com google gms google services 4 1 0 在以下位置进

随机推荐