ffmpeg系列-视频旋转角度实现

版权声明: https://blog.csdn.net/u013470102/article/details/89473570

一app开发,火急火燎的拿来一个视频,说录制的视频播放角度都不正常。拿过来一看,确实,角度是歪的,用系统的mediaplayer一试,是正常的。把视频放到ffmpeg中,可以看到视频metadata下视频旋转角度是90度。

image
ijk中有提供视频角度旋转的接口:

 //开启自动旋转,这里旋转的是视频
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);

//关闭自动旋转
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);

那么我们看下这个接口做了什么呢?
这个在recreate_format_l/ffpipenode_android_mediacodec_vdec.c函数中

//获取视频旋转角度
    rotate_degrees = ffp_get_video_rotate_degrees(ffp);
    //如果上层开启旋转,也就是上面设置的2个接口,同时视频角度不为0
    if (ffp->mediacodec_auto_rotate &&
        rotate_degrees != 0 &&
        SDL_Android_GetApiLevel() >= IJK_API_21_LOLLIPOP) {
        ALOGI("amc: rotate in decoder: %d\n", rotate_degrees);
        opaque->frame_rotate_degrees = rotate_degrees;
        //把获取的视频角度设置给mediaformat
        SDL_AMediaFormat_setInt32(opaque->input_aformat, "rotation-degrees", rotate_degrees);
        //通知上层,视频角度改变了
        ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, 0);
    } else {
        ALOGI("amc: rotate notify: %d\n", rotate_degrees);
        ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, rotate_degrees);
    }

看一下获取视频角度ffp_get_video_rotate_degrees/ff_ffplay.c函数:

//获取视频角度
int ffp_get_video_rotate_degrees(FFPlayer *ffp)
{
    VideoState *is = ffp->is;
    if (!is)
        return 0;
//获取的角度%360度,不足的还是原来的值
    int theta  = abs((int)((int64_t)round(fabs(get_rotation(is->video_st))) % 360));
    switch (theta) {
    //如果角度是0 90 180 270度,则不处理,直接跳出来
        case 0:
        case 90:
        case 180:
        case 270:
            break;
            //如果角度是360度,则置0
        case 360:
            theta = 0;
            break;
        default://或者置0
            ALOGW("Unknown rotate degress: %d\n", theta);
            theta = 0;
            break;
    }

    return theta;
}

继续跟踪函数get_rotation/ff_cmdutils.c函数

double get_rotation(AVStream *st)
{
//从metadata的rotate获取视频旋转角度
    AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, "rotate", NULL, 0);
    uint8_t* displaymatrix = av_stream_get_side_data(st,
                                                     AV_PKT_DATA_DISPLAYMATRIX, NULL);
    double theta = 0;

    if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
        char *tail;
        theta = av_strtod(rotate_tag->value, &tail);
        if (*tail)
            theta = 0;
    }
    if (displaymatrix && !theta)
        theta = -av_display_rotation_get((int32_t*) displaymatrix);

    theta -= 360*floor(theta/360 + 0.9/360);

    if (fabs(theta - 90*round(theta/90)) > 2)
        av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n"
               "If you want to help, upload a sample "
               "of this file to ftp://upload.ffmpeg.org/incoming/ "
               "and contact the ffmpeg-devel mailing list. ([email protected])");

    return theta;
}

那么从上面我们就可以知道,视频的整个旋转流程就是从metadata中获取rotate,也就是拿到视频的角度,然后在创建mediaformat的时候,设置给mediaformat。这样就改变了视频的旋转角度。那么应用上层做了针对重力的视频旋转,这个有没有问题呢?目前没收到反馈。

猜你喜欢

转载自blog.csdn.net/u013470102/article/details/89473570
今日推荐