ffmpeg解码视频帧旋转角度

ffmpeg解码视频帧旋转角度

常见视频,有部分视频带有角度的,在ffmpeg视频流在获取AVFormatContext信息是可以获取角度信息,通过这个角度在播放器会进行旋转,不然你播放视频有角度视频

获取旋转角度

在这个格式上下文AVFormatContext *pFormatCtx 可以获取相应的信息,下面获取视频角度方法封装

int WlFFmpeg::getRotate(){
    AVDictionaryEntry *tag = NULL;
    int m_Rotate=0;
    tag = av_dict_get(pFormatCtx->metadata, "rotate", tag, 0);

    if (tag==NULL)
    {
        if(LOG_DEBUG)
        {
            LOGE("==========tag is null");
        }

        m_Rotate = 0;
    }
    else
    {
        int angle = atoi(tag->value);
        if(LOG_DEBUG)
        {
            LOGE("===========angle==:%d",angle);
        }
        angle %= 360;
        if (angle == 90)
        {
            m_Rotate = 90;
        }
        else if (angle == 180)
        {
            m_Rotate = 180;
        }
        else if (angle == 270)
        {
            m_Rotate = 270;
        }
        else
        {
            m_Rotate = 270;
        }
    }
    return m_Rotate;

}

视频角度旋转方法90、180、270

手动AVFrame进行旋转存储数据

/**
 * 逆时针旋转90
 * @param src
 * @param des
 */
void WlVideo::frame_rotate_90(AVFrame *src, AVFrame *des) {
    int n = 0;
    int hw = src->width >> 1;
    int hh = src->height >> 1;
    int size = src->width * src->height;
    int hsize = size >> 2;

    int pos = 0;
    //copy y
    for (int j = 0; j < src->width; j++) {
        pos = size;
        for (int i = src->height - 1; i >= 0; i--) {
            pos -= src->width;
            des->data[0][n++] = src->data[0][pos + j];
        }
    }
    //copy uv
    n = 0;
    for (int j = 0; j < hw; j++) {
        pos = hsize;
        for (int i = hh - 1; i >= 0; i--) {
            pos -= hw;
            des->data[1][n] = src->data[1][pos + j];
            des->data[2][n] = src->data[2][pos + j];
            n++;
        }
    }

    des->linesize[0] = src->height;
    des->linesize[1] = src->height >> 1;
    des->linesize[2] = src->height >> 1;
    des->height = src->width;
    des->width = src->height;
}

void WlVideo::frame_rotate_180(AVFrame *src, AVFrame *des) {
    int n = 0, i = 0, j = 0;
    int hw = src->width >> 1;
    int hh = src->height >> 1;
    int pos = src->width * src->height;

    for (i = 0; i < src->height; i++) {
        pos -= src->width;
        for (int j = 0; j < src->width; j++) {
            des->data[0][n++] = src->data[0][pos + j];
        }
    }

    n = 0;
    pos = src->width * src->height >> 2;

    for (i = 0; i < hh; i++) {
        pos -= hw;
        for (int j = 0; j < hw; j++) {

            des->data[1][n] = src->data[1][pos + j];
            des->data[2][n] = src->data[2][pos + j];
            n++;
        }
    }

    des->linesize[0] = src->width;
    des->linesize[1] = src->width >> 1;
    des->linesize[2] = src->width >> 1;

    des->width = src->width;
    des->height = src->height;
    des->format = src->format;

    des->pts = src->pts;
    des->pkt_pts = src->pkt_pts;
    des->pkt_dts = src->pkt_dts;

    des->key_frame = src->key_frame;
}

void WlVideo::frame_rotate_270(AVFrame *src, AVFrame *des) {
    int n = 0, i = 0, j = 0;
    int hw = src->width >> 1;
    int hh = src->height >> 1;
    int pos = 0;

    for (i = src->width - 1; i >= 0; i--) {
        pos = 0;
        for (j = 0; j < src->height; j++) {
            des->data[0][n++] = src->data[0][pos + i];
            pos += src->width;
        }
    }

    n = 0;
    for (i = hw - 1; i >= 0; i--) {
        pos = 0;
        for (j = 0; j < hh; j++) {
            des->data[1][n] = src->data[1][pos + i];
            des->data[2][n] = src->data[2][pos + i];
            pos += hw;
            n++;
        }
    }

    des->linesize[0] = src->height;
    des->linesize[1] = src->height >> 1;
    des->linesize[2] = src->height >> 1;

    des->width = src->height;
    des->height = src->width;
    des->format = src->format;

    des->pts = src->pts;
    des->pkt_pts = src->pkt_pts;
    des->pkt_dts = src->pkt_dts;

    des->key_frame = src->key_frame;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用FFmpeg解码B帧和视频抽帧,可以结合使用avcodec_send_packet()和avcodec_receive_frame()函数进行解码,然后使用av_write_frame()函数将解码后的帧写入输出文件。具体步骤如下: 1. 初始化FFmpeg ``` av_register_all(); avcodec_register_all(); ``` 2. 打开输入文件 ``` AVFormatContext *inputFormatCtx = NULL; avformat_open_input(&inputFormatCtx, inputFilePath, NULL, NULL); avformat_find_stream_info(inputFormatCtx, NULL); ``` 3. 找到视频流 ``` AVCodec *inputCodec = NULL; int videoStreamIndex = av_find_best_stream(inputFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &inputCodec, 0); AVCodecContext *inputCodecCtx = inputFormatCtx->streams[videoStreamIndex]->codec; ``` 4. 打开解码器 ``` avcodec_open2(inputCodecCtx, inputCodec, NULL); ``` 5. 初始化输出文件 ``` AVFormatContext *outputFormatCtx = NULL; avformat_alloc_output_context2(&outputFormatCtx, NULL, NULL, outputFilePath); avio_open(&outputFormatCtx->pb, outputFilePath, AVIO_FLAG_WRITE); ``` 6. 写入输出文件头 ``` avformat_write_header(outputFormatCtx, NULL); ``` 7. 读取帧数据并解码 ``` AVPacket packet; AVFrame *frame = av_frame_alloc(); while (av_read_frame(inputFormatCtx, &packet) == 0) { if (packet.stream_index == videoStreamIndex) { avcodec_send_packet(inputCodecCtx, &packet); while (avcodec_receive_frame(inputCodecCtx, frame) == 0) { // do something with the decoded frame, e.g. write to output file av_write_frame(outputFormatCtx, frame); } } av_packet_unref(&packet); } ``` 8. 写入输出文件尾 ``` av_write_trailer(outputFormatCtx); ``` 9. 释放资源 ``` avformat_close_input(&inputFormatCtx); avcodec_free_context(&inputCodecCtx); avformat_free_context(inputFormatCtx); avformat_free_context(outputFormatCtx); av_frame_free(&frame); ``` 这样,就可以使用FFmpeg解码B帧和视频抽帧了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baoyu45585

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值