【FFMPEG应用篇】基于FFmpeg的转码应用(FLV MP4)

这篇具有很好参考价值的文章主要介绍了【FFMPEG应用篇】基于FFmpeg的转码应用(FLV MP4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 方法声明

extern "C"   //ffmpeg使用c语言实现的,引入用c写的代码就要用extern
{
#include <libavcodec/avcodec.h>   //注册
#include <libavdevice/avdevice.h>  //设备
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#include<iostream>

class fcoverh264
{
public:
    fcoverh264(int number);

    //打开H264视频文件
    void openFile(std::string file);
    //根据我们需要的封装格式进行处理
    void outPut(std::string fileout);
private:
    AVFormatContext* forContext, * formatout;//保存数据的结构体 forContext存输入进来的视频信息;formatout存储最终输出的视频信息
    AVPacket* pkt;//pkt
    int videoType;
};

 定义实现 

#include "fcoverh264.h"


extern "C"   //ffmpeg使用c语言实现的,引入用c写的代码就要用extern
{
#include <libavcodec/avcodec.h>   //注册
#include <libavdevice/avdevice.h>  //设备
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
fcoverh264::fcoverh264(int number):videoType(number)
{
    /*
     * 转码的流程:
     * 1.注册组件
     * 2.打开视频流 打开视频文件
     * 3.查找有没有流数据
     * 4.查找视频码流数据
     *
     * 6.根据要的封装格式 来猜测格式对应编辑器
     * 7.打开对应文件
     * 8.新建流
     * 9.写入头部信息
     * 10.读取一帧一帧的码流数据
     * 11.转码---->时间基的转化
     * 所以在解码的时候:显示顺序和解码的顺序是一样的;
       处理其他视频的时候:就需要关注 显示顺序和解码的顺序是否一致了
       编码有B帧? 解码:IPB
     * 12.写入对应的一帧数据到文件中
     */

     //注册组件
    av_register_all();
    forContext = avformat_alloc_context();

}

void fcoverh264::openFile(std::string file)
{
    //打开输入视频
    int res = avformat_open_input(&forContext, file.c_str(), nullptr, nullptr);
    //判断是否打开成功
    if (res < 0)
    {
        std::cout << "打开失败"<<std::endl;
        return;
    }

    //打开视频文件成功,获取文件信息
    res = avformat_find_stream_info(forContext, nullptr);//查看有没有相关视频流信息
    if (res < 0)//判断是否有流媒体
    {
        std::cout << "没有流媒体信息" << std::endl;
        return;
    }

    //一个视频流有多股码流,存在forContentext中streams数组中
    /*int videoType = -1;*/
    for (int i = 0; i < forContext->nb_streams; i++) //i小于流的个数
    {
        if (forContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//视频流
        {
            videoType = i;//标识类型
            break;
        }
    }
    if (videoType == -1)
    {
        std::cout << "没有视频流相关信息" << std::endl;
        return;
    }
    std::cout << "输入的准备已经完成"<<std::endl;
}

//根据我们需要的封装格式进行处理
void fcoverh264::outPut(std::string fileout)
{
    //猜测编码器
    AVOutputFormat* avformat = av_guess_format(nullptr, fileout.c_str(), nullptr);
    if (avformat == nullptr)
    {
        std::cout << "没有编码器!"<<std::endl;
        return;
    }
    std::cout << "AVOutputFormat"<<std::endl;

    //保存输出视频信息的结构体
    formatout = avformat_alloc_context();
    //设置输出格式
    formatout->oformat = avformat;

    //打开视频流 文件流
    //参数1:输入输出的上下文对象
    //参数2:文件流路径
    //参数3:文件打开格式 写的方式
    int res = avio_open(&formatout->pb, fileout.c_str(), AVIO_FLAG_WRITE);
    if (res < 0)
    {
        std::cout << "open file error"<<std::endl;
        return;
    }
    std::cout << "avio_open"<<std::endl;
    //新建视频流
    //参数1:视频信息结构体
    //参数2:新建流 的 返回新建流 的地址
    AVStream* newStream = avformat_new_stream(formatout, nullptr);
    if (newStream == nullptr)
    {
        std::cout << "打开视频流失败"<<std::endl;
        return;
    }
    std::cout << "newStream"<<std::endl;
    //编码器对应参数设置  拷贝参数设置   newStream:输入进入流的参数设置
    res = avcodec_parameters_copy(newStream->codecpar, forContext->streams[videoType]->codecpar);
    std::cout << "res=" << res<<std::endl;
    if (res < 0)
    {
        std::cout << "拷贝失败!"<< std::endl;
        return;
    }
    std::cout << "res=" << res<<std::endl;
    //设置新的流里面 codec_tag 设置为0
    newStream->codecpar->codec_tag = 0;

    //头部信息写入----写入成功与否
    res = avformat_write_header(formatout, nullptr);//formatout封装格式的结构体
    //判断写入成功与否
    if (res < 0)
    {
        std::cout << "写入头部信息失败!" <<std::endl;
        return;
    }
    std::cout << "res=" << res << std::endl;

    //开始读取码流数据
    pkt = (AVPacket*)malloc(sizeof(AVPacket));
    //算出这张图有多大
    int size = newStream->codecpar->width * newStream->codecpar->height;
    av_new_packet(pkt, size);

    int frameCount = 0;

    //一帧一帧的读取
    while (av_read_frame(forContext, pkt) == 0)
    {
        //判断这一帧这是不是视频流
        if (pkt->stream_index == videoType)
        {
            frameCount++;
            //如果是视频流----判断有没有设置过 时间基
            if (pkt->pts == AV_NOPTS_VALUE)
            {
                //时间基  time_base AVRational属性
                AVRational timebase = forContext->streams[videoType]->time_base;
                //计算帧之间的长度(duration)   double强制转换
                int64_t duration = (double)AV_TIME_BASE / av_q2d(forContext->streams[videoType]->r_frame_rate);
                //计算显示时间基(pts):公式:(当前帧数*两帧之间的长度))/(输入时间基*AV_TIME_BASE)
                pkt->pts = (double)(frameCount * duration) / (av_q2d(timebase) * AV_TIME_BASE);
                //解码时间基(dts)
                pkt->dts = pkt->pts;
                //目标两帧之间的长度
                pkt->duration = duration / (double)(av_q2d(timebase) * AV_TIME_BASE);
            }
            else if (pkt->pts < pkt->dts)//显示 时间基 小于 解码时间基 不要这样子的
            {
                continue;
            }
            //上述步骤为  时间基设置



            //解码 时间基 真正的转换 如下:

            //显示时间基的转换
            pkt->pts = av_rescale_q_rnd(pkt->pts, forContext->streams[videoType]->time_base,
                newStream->time_base, (AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
            //解码时间基的转换
            pkt->dts = av_rescale_q_rnd(pkt->dts, forContext->streams[videoType]->time_base,
                newStream->time_base, (AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
            //数据时长设置
            pkt->duration = av_rescale_q(pkt->duration, forContext->streams[videoType]->time_base,
                newStream->time_base);
            //数据位置的设置 数据在流信息中的设置
            pkt->pos = -1;
            //数据包的标记:结合AV_PKT_FLAG_KEY使用  最小为1表示这一帧是一个关键帧
            pkt->flags |= AV_PKT_FLAG_KEY;
            //标记:当前写入的这一帧是视频流
            pkt->stream_index = 0;

            //转码后的数据包 写入 目标视频信息 结构体 中
            av_interleaved_write_frame(formatout, pkt);
        }
        //清空处理:重新设置包
        av_packet_unref(pkt);
    }

    //写入尾巴帧
    av_write_trailer(formatout);

    //用完之后进行 关闭 处理 :关闭猜测完的流
    avio_close(formatout->pb);//对应avio_open()
    std::cout << "avio_close"<<std::endl;

    //释放malloc的空间 释放保存信息的结构体
    av_free(formatout);
    std::cout << "av_free"<<std::endl;

    //关闭输入流
    avformat_close_input(&forContext);//对应avformat_open_inpu
    std::cout << "avformat_close_input"<<std::endl;

    //释放forContext结构体空间
    av_free(forContext);
    std::cout << "av_free"<<std::endl;
}

 调用实例文章来源地址https://www.toymoban.com/news/detail-781860.html

#include <iostream>
#include "fcoverh264.h"


int main() {

    fcoverh264* cover = new fcoverh264{-1};       //转码
    cover->openFile("test01.h264");
    cover->outPut("code_frame.flv");

    return 0;
}

到了这里,关于【FFMPEG应用篇】基于FFmpeg的转码应用(FLV MP4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python ffmpeg将mp4文件实时转码为ts,并指定pid等信息,输出到udp

    要将MP4文件实时转码为TS格式,并将PID等信息指定为UDP输出,可以使用 subprocess 模块和ffmpeg命令行工具来实现。以下是一个示例代码,用于实时转码并将输出发送到UDP服务器: 在上述代码中,我们首先定义了输入文件、UDP服务器地址和PID等信息。然后,我们使用 subprocess.Pop

    2024年01月22日
    浏览(62)
  • DXGI高帧率屏幕录像软件源码解析(声音捕获,抓屏,ffmpeg录像,MP4录像,flv录像,麦克风采集)(第4篇编码,录像部分)

    本文DEMO源码下载: https://download.csdn.net/download/xjb2006/85109025 dxgi桌面屏幕录像(windows屏幕录像,硬件编码,声音捕获,音视频同步) 由于篇幅有限,分为4篇发表: 1、SDK接口一览: 2、声音采集部分: 3、屏幕捕获部分: 4、编码,录像部分: 距离上篇文章已经过了快1年了,才

    2023年04月17日
    浏览(52)
  • 基于FFmpeg的封装格式MP4(TS)

    每一帧音频或视频都有一个持续时间:duration: 采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。 。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8k

    2024年02月03日
    浏览(47)
  • FFmpeg4入门13:h264编码为mp4

    上一篇将yuv源视频文件编码为 *.h264 的由libx264实现压缩的文件,将源文件从55M编码为620KB,但是h264文件只有视频数据,而且使用范围不太广。那么就需要进一步的封装,在此选用最常用的mp4格式为例。 随便选一个mp4格式文件,用FFmpeg4入门4:解析视频并输出视频信息或者ffp

    2023年04月10日
    浏览(88)
  • 视频转码:掌握mp4视频格式转FLV视频的技巧,视频批量剪辑方法

    在多媒体时代,视频格式的转换成为一种常见的需求。把MP4格式转换为FLV格式,FLV格式的视频文件通常具有较小的文件大小,同时保持了较好的视频质量。批量剪辑视频的方法能大大提高工作效率。下面来看云炫AI智剪如何进行MP4到FLV的转码,如何批量剪辑视频的方法。 转码

    2024年01月19日
    浏览(62)
  • FFmpeg从入门到入魔(3):提取MP4中的H.264和AAC

        最近在开发中遇到了一个问题,即无法提取到MP4中H264流的关键帧进行处理,且保存到本地的AAC音频也无法正常播放。经过调试分析发现,这是由于解封装MP4得到的H264和AAC是ES流,它们缺失解码时必要的 起始码 / SPS / PPS 和 adts头 。 1. MP4格式解析 1.1 MP4简介  MP4封装格式是

    2023年04月16日
    浏览(49)
  • FFMPEG mp4封装实现

    FFMPEG mp4录像 author:lyn date:2022.09.28 version: ffmpeg4.1.3 1.mp4数据结构 2.ffmpeg mp4封装实现 3.mp4函数调用关系 4.参考资料 1.mp4数据结构 1.1mp4简介 MP4或称MPEG-4第14部分(英语:MPEG-4 Part 14)是一种标准的数字多媒体容器格式。MPEG-4第14部分的扩展名为 .mp4 ,以存储数字音频及数字视频

    2023年04月08日
    浏览(37)
  • ffmpeg操作MP4视频封面

    提取视频封面 视频流中提取帧图 3.重新设置视频封面 更多参考: https://blog.csdn.net/m0_37624402/article/details/125123818

    2024年02月04日
    浏览(44)
  • 20231005使用ffmpeg旋转MP4视频

    20231005使用ffmpeg旋转MP4视频 2023/10/5 12:21 百度搜搜:ffmpeg 旋转90度 https://zhuanlan.zhihu.com/p/637790915 【FFmpeg实战】FFMPEG常用命令行 https://blog.csdn.net/weixin_37515325/article/details/127817057 FFMPEG常用命令行 5.视频旋转 顺时针旋转90度:ffmpeg -i test.mp4 -vf \\\"transpose=1\\\" out.mp4//顺时针旋转90° 逆时针

    2024年02月07日
    浏览(49)
  • ffmpeg批量转换mpg为mp4

    1、新建一个txt文件,并复制如下代码进入,然后保存。 2、把文件后缀修改为bat 。 3、把后缀为bat的文件放到要批量处理的视频文件夹里面。 4、在确保安装了ffmpeg的情况下,双击bat文件执行即可。 5、参数说明: -i          输入文件,这里指的就是视频文件。 -y       

    2024年02月13日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包