Android-video rotation详解

前言:

  不知你有没有注意到,每次用相机竖屏录制1080p的视频时,录制的mp4文件显示都是1920x1080,我们手机的屏幕都是横向小于竖向的,那么怎么播放这个1920x1080的视频呢?这就涉及到了rotation的概念。rotation表示视频的角度,当视频角度为90度的时候在显示时就是旋转90度播放的。具体是怎么实现的呢?本文将带你去了解。

 

一个疑问:

  看到这里,我很好奇,为什么录制视频时非要1920x1080,rotation是90,不能录制1080x1920,然后rotation是0吗?后者还不需要播放时做处理。

  一番研究才发现,确实不能这样。

  录制视频的过程,首先我们需要用相机捕获画面,此时需要用到camera sensor,camera sensor是由很多个感光元件组成的,一些常用sensor的具体设置如下:

从上面的数据可以发现sensor的感光元件w一般都大于h,手机相机也是如此。

当我们设置尺寸为1920x1080时,sensor获取数据之后稍作裁剪再downscale即可,但是如果设置成1080x1920那么需要裁剪的数据较多,就会很大程度上损失fov。所以手机录制的视频都是w>h的。

 

对rotation的处理:

  对于rotation不为0的视频,是什么时候做的旋转呢?解码前?decoder中解码后?还是surface中?

  显然,不可能是解码前,因为码流数据很难处理。那么我们看看,ACodec对rotation的具体处理:

// frameworks/av/media/libstagefright/ACodec.cpp
status_t ACodec::configureCodec(
        const char *mime, const sp<AMessage> &msg) {
    .......
    int32_t rotationDegrees;
    if (msg->findInt32("rotation-degrees", &rotationDegrees)) { // 读取rotation
        mRotationDegrees = rotationDegrees;
    } else {
        mRotationDegrees = 0;
    }
    .......
}

status_t ACodec::setupNativeWindowSizeFormatAndUsage(
        ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */,
        bool reconnect) {
    .......
    return setNativeWindowSizeFormatAndUsage( // 将rotation设置给nativewindow
            nativeWindow,
            def.format.video.nFrameWidth,
            def.format.video.nFrameHeight,
            def.format.video.eColorFormat,
            mRotationDegrees,
            usage,
            reconnect);
}

// frameworks/av/media/libstagefright/SurfaceUtils.cpp
status_t setNativeWindowSizeFormatAndUsage(
        ANativeWindow *nativeWindow /* nonnull */,
        int width, int height, int format, int rotation, int usage, bool reconnect) {
    ......
    // 根据rotation判断transform
    int transform = 0;
    if ((rotation % 90) == 0) {
        switch ((rotation / 90) & 3) {
            case 1:  transform = HAL_TRANSFORM_ROT_90;  break;
            case 2:  transform = HAL_TRANSFORM_ROT_180; break;
            case 3:  transform = HAL_TRANSFORM_ROT_270; break;
            default: transform = 0;                     break;
        }
    }

    err = native_window_set_buffers_transform(nativeWindow, transform);
    ......
}

// frameworks/native/libs/nativewindow/include/system/window.h
static inline int native_window_set_buffers_transform(
        struct ANativeWindow* window,
        int transform)
{
    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
            transform);
}

// frameworks/native/libs/gui/Surface.cpp
int Surface::perform(int operation, va_list args)
{
    int res = NO_ERROR;
    switch (operation) {
    ......
    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
        res = dispatchSetBuffersTransform(args);
        break;
    ......
}
int Surface::dispatchSetBuffersTransform(va_list args) {
    uint32_t transform = va_arg(args, uint32_t);
    return setBuffersTransform(transform);
}

具体过程如下:

step1: APP解析头文件,解析到video的rotation

step2: APP播放视频时调用mediacodec的configure函数,并把rotation传入

step3: MediaCodec ACodec对收到的消息进行处理,获取到rotation的信息。

step4: ACodec在创建nativewindow时将rotation信息传入。

step5: surface把rotation信息转换为transform的角度

step6: 播放视频时每解码完一帧就会把yuv数据送给surface去渲染,此时surface会根据设置的transform的角度旋转yuv数据并render。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值