ffmpeg日记4001-原理介绍-视频切割原理

原理

打开输入---->打开输出---->根据输入来创建流---->拷贝流设置---->循环读帧---->判断时间点是否到达切割点,并做设置---->设置pts和dts---->写入---->善后

重点是pts和dts如何设置。参考《ffmpeg学习日记25-pts,dts概念的理解》

在这里插入图片描述

示例代码

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

project(clipVideo )

#set(CMAKE_CXX_STANDARD 11)
#set(CMAKE_CXX_STANDARD_REQUIRED YES)

set(CMAKE_AUTOMOC ON) # Meta-Object Compiler
set(CMAKE_AUTORCC ON) # Resource Compiler
set(CMAKE_AUTOUIC ON) # User Interface Compiler

set(CMAKE_BUILD_TYPE Debug)

#find_package(PkgConfig REQUIRED)
#pkg_check_modules(AVLIB REQUIRED IMPORTED_TARGET libavcodec libavformat libavutil libswresample libswscale)

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
        set(CURRENT_SYSTEM Linux)
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
        set(CURRENT_SYSTEM Windows)
endif()

set(FFMPEG_LIB_DIR ${PROJECT_SOURCE_DIR}/../../lib)
set(FFMPEG_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/../../include)

include_directories(
    ${PROJECT_SOURCE_DIR}
#    ${PROJECT_SOURCE_DIR}/../../include
    ${FFMPEG_INCLUDE_DIR}
    )

link_libraries(
#    ${PROJECT_SOURCE_DIR}/../../lib
    ${FFMPEG_LIB_DIR}
    )

#对于find_package找不到的外部依赖库,可以用add_library添加
# SHARED表示添加的是动态库
# IMPORTED表示是引入已经存在的动态库

add_library( avcodec STATIC IMPORTED)
add_library( avfilter STATIC IMPORTED )
add_library( swresample STATIC IMPORTED )
add_library( swscale STATIC IMPORTED )
add_library( avformat STATIC IMPORTED )
add_library( avutil STATIC IMPORTED )


#指定所添加依赖库的导入路径
set_target_properties( avcodec PROPERTIES IMPORTED_LOCATION ${FFMPEG_LIB_DIR}/avcodec.lib )
set_target_properties( avfilter PROPERTIES IMPORTED_LOCATION ${FFMPEG_LIB_DIR}/avfilter.lib )
set_target_properties( swresample PROPERTIES IMPORTED_LOCATION ${FFMPEG_LIB_DIR}/swresample.lib )
set_target_properties( swscale PROPERTIES IMPORTED_LOCATION ${FFMPEG_LIB_DIR}/swscale.lib )
set_target_properties( avformat PROPERTIES IMPORTED_LOCATION ${FFMPEG_LIB_DIR}/avformat.lib )
set_target_properties( avutil PROPERTIES IMPORTED_LOCATION ${FFMPEG_LIB_DIR}/avutil.lib )


add_executable(${PROJECT_NAME} main.cpp)

target_link_libraries(${PROJECT_NAME}
    avcodec avfilter avformat avutil
#    postproc swresample swscale
    )

main.cpp

#include <iostream>
#include <cinttypes>

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include "libavutil/avutil.h"

#include <libavcodec/avcodec.h>

#include <libavformat/avformat.h>
#include <libavformat/avio.h>

#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>

#include <libavutil/timestamp.h>

#include <libavutil/time.h>
#include <libavutil/pixdesc.h>
#include <libavutil/audio_fifo.h>
#include <libavutil/avassert.h>
#include <libavutil/avstring.h>
#include <libavutil/frame.h>
#include <libavutil/opt.h>

#include <libswresample/swresample.h>

#ifdef __cplusplus
}
#endif

#ifdef _WIN32
#include <direct.h>
#elif __APPLE__ || __linux__
#include<unistd.h>
#endif

using namespace std;

int main()
{
    cout << "Hello World!" << endl;
    printf("ffmpeg version:%s\n",av_version_info());

    std::cout << "current path:" << getcwd(NULL,0) << std::endl;

    int ret = 0;
    float fromSeconds = 3.0,endSeconds = 8.0;

    AVFormatContext *ifmt_ctx = NULL,*ofmt1_ctx = NULL;
    std::string ifileName = "../../../15s.mp4",ofileName1 = "1.mp4";
    AVPacket pkt;

    if ( (ret = avformat_open_input(&ifmt_ctx,ifileName.c_str(),NULL,NULL)) < 0){
        std::cout << "can not open the in put file format context!" << std::endl;
        return 0;
    }

    if( (ret = avformat_find_stream_info(ifmt_ctx,NULL)) < 0){
        std::cout << "can not find the input stream info" << std::endl;
        return 0;
    }

    avformat_alloc_output_context2(&ofmt1_ctx,NULL,NULL,ofileName1.c_str());
    if(!ofmt1_ctx){
        std::cout << "could not creat output1 context" << std::endl;
        return 0;
    }


    //拷贝参数到输出结构
    for(int i = 0;i < ifmt_ctx->nb_streams;i++){
        AVStream *instream = ifmt_ctx->streams[i];
        AVCodec *codec = avcodec_find_decoder(instream->codecpar->codec_id);
        AVStream *outStream = avformat_new_stream(ofmt1_ctx,codec);
        if(!outStream){
            std::cout << "failed allow output stream" << std::endl;
            return 0;
        }

        AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
        ret = avcodec_parameters_to_context(codecCtx,instream->codecpar);
        if(ret < 0){
            std::cout << "failed to copy instream codecpar to codec context" << std::endl;
            return 0;
        }

        //这一步是在干什么呢
        codecCtx->codec_tag = 0;//这个标志是什么意思???
        if (ofmt1_ctx->oformat->flags & AVFMT_GLOBALHEADER){
            codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
        }

        ret = avcodec_parameters_from_context(outStream->codecpar,codecCtx);
        if (ret < 0){
            std::cout << "failed to copy codec context to outstram codecpar context" << std::endl;
            return 0;
        }
    }

    av_dump_format(ofmt1_ctx,0,ofileName1.c_str(),1);

    if(!(ofmt1_ctx->flags & AVFMT_NOFILE)){
        ret = avio_open(&ofmt1_ctx->pb,ofileName1.c_str(),AVIO_FLAG_WRITE);
        if (ret < 0){
            std::cout << "could not open output 1.mp4" << std::endl;
            return 0;
        }
    }


    //写文件头
    ret = avformat_write_header(ofmt1_ctx,NULL);
    if (ret < 0){
        std::cout << "error write header of 1.mp4" << std::endl;
        return 0;
    }

    ret = av_seek_frame(ifmt_ctx, -1, (int64_t)(fromSeconds * AV_TIME_BASE), AVSEEK_FLAG_ANY);
    std::cout << "ret:" << ret << std::endl;

    int64_t *dstStartFrom = (int64_t *)malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
    memset(dstStartFrom, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
    int64_t *ptsStartFrom = (int64_t *)malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
    memset(ptsStartFrom, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);


    while(1){
        AVStream *instream,*outstream;
        ret = av_read_frame(ifmt_ctx,&pkt);
        if (ret < 0)
            break;
        std::cout << "pkt.pts:" << pkt.pts << std::endl;
        instream = ifmt_ctx->streams[pkt.stream_index];
        outstream = ofmt1_ctx->streams[pkt.stream_index];

        if (av_q2d(instream->time_base) * pkt.pts > endSeconds){
            av_packet_unref(&pkt);
            break;
        }

        if (dstStartFrom[pkt.stream_index] == 0)
        {
            dstStartFrom[pkt.stream_index] = pkt.dts;
//          /  printf("dstStartFrom: %s\n", av_strerror(dstStartFrom[pkt.stream_index]));
        }
        if (ptsStartFrom[pkt.stream_index] == 0)
        {
            ptsStartFrom[pkt.stream_index] = pkt.dts;
//            printf("ptsStartFrom: %s\n", av_strerror(ptsStartFrom[pkt.stream_index]));
        }


        pkt.pts = av_rescale_q_rnd(pkt.pts - ptsStartFrom[pkt.stream_index],instream->time_base,outstream->time_base,
                                   (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) );//
        pkt.dts = av_rescale_q_rnd(pkt.dts - dstStartFrom[pkt.stream_index],instream->time_base,outstream->time_base,
                                   (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) );

        if (pkt.pts < 0){
            pkt.pts = 0;
        }
        if(pkt.dts < 0){
            pkt.dts = 0;
        }

        pkt.duration = (int)av_rescale_q( (int64_t)pkt.duration ,
                                          instream->time_base,
                                          outstream->time_base);

        pkt.pos = -1;

        ret = av_interleaved_write_frame(ofmt1_ctx,&pkt);
        if(ret){
            std::cout << "error muxing packet" << std::endl;
            break;
        }
        av_packet_unref(&pkt);
    }
    //写文件尾
    free(dstStartFrom);
    free(ptsStartFrom);
    av_write_trailer(ofmt1_ctx);

    //释放资源
    avformat_close_input(&ifmt_ctx);
    if (ofmt1_ctx && !(ofmt1_ctx->flags & AVFMT_NOFILE)){
        avio_closep(&ofmt1_ctx->pb);
    }
    avformat_free_context(ofmt1_ctx);
    return 0;
}

总结

  1. 这里的操作是将一种视频格式切割,之后生成的视频是同样的格式,所以直接是参数的复制即可,如果要生成另一种格式的视频,应该要单独设置设置输出视频格式的参数。

参考

  • ffmpeg实现视频切割

  • FFmpeg ‘avcodec_copy_context’ deprecated (视频裁剪)

  • av_seek_frame使用详解

  • FFmpeg中的时间基(time_base), AV_TIME_BASE

  • FFmpeg之时间戳详解


  • 在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/449396.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HBase非关系型数据库

HBase非关系型数据库 1 什么是HBase2 HBase的特点3 什么时候需要HBase4 HBase的数据模型5 HBase架构5.1 架构5.2 HBase如何列式储存 6 如何正确设计RowKey 1 什么是HBase HBase – Hadoop Database&#xff0c;是一个高可靠性、高性能、面向列、可伸缩、 实时读写的分布式数据…

Java并发编程: AQS

文章目录 一、前置知识二、什么是AQS三、使用AQS框架的锁和同步器1、ReentrantLock2、ReentrantReadWriteLock3、CountDownLatch4、CyclicBarrier5、Semaphore&#xff1a;信号量 四、锁和同步器的关系1、锁&#xff1a;面向锁的使用者2、同步器&#xff1a;面向锁的实现者 五、…

Material UI 5 学习03-Text Field文本输入框

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Text Field文本输入框 一、最基本的本文输入框1、基础示例2、一些表单属性3、验证 二、多行文本 一、最基本的本文输入框 1、基础示例 import {Box, TextField} from "…

九、ELMo 语言模型

ELMo&#xff08;Embeddings from Language Models&#xff09;兼顾了两个问题&#xff1a;一是词语用法在语义和语法上的复杂特点&#xff1b;二是随着语言环境的改变&#xff0c;这些用法也应该随之改变&#xff0c;解决多义词的问题。 ELMo 语言模型原理图&#xff1a; ELMo…

Matlab如何批量读取Excel数据?科研效率UpUp第3期

上一篇文章中&#xff0c;讲了如何批量统计一组Excel数据中多个站位所有物种的数量之和&#xff08;Matlab如何高效统计多站数据中各站目标总数&#xff1f;科研效率UpUp第2期&#xff09;。 进一步&#xff0c;假如我们有多组Excel数据&#xff0c;也就是多个Excel表格&#…

【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-先导篇)

专栏系列文章推荐&#xff1a; 2024高级系统架构设计师备考资料&#xff08;高频考点&真题&经验&#xff09;https://blog.csdn.net/seeker1994/category_12601310.html 案例分析篇01&#xff1a;软件架构设计考点架构风格及质量属性&#xff08;2024年软考高级系统…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Navigation)

Navigation组件是路由导航的根视图容器&#xff0c;一般作为Page页面的根容器使用&#xff0c;其内部默认包含了标题栏、内容区和工具栏&#xff0c;其中内容区默认首页显示导航内容&#xff08;Navigation的子组件&#xff09;或非首页显示&#xff08;NavDestination的子组件…

使用 Amazon Bedrock 和 RAG 构建 Text2SQL 行业数据查询助手

背景 随着企业数据量的持续增长&#xff0c;如何让非技术人员也能轻松分析数据、获得商业洞察成为了当前的痛点。本文将介绍如何使用亚马逊云科技的大语言模型服务 Amazon Bedrock 以及 RAG (Retrieval Augmented Generation)&#xff0c;实现 Text2SQL 功能&#xff0c;以此为…

图论(二)之最短路问题

最短路 Dijkstra求最短路 文章目录 最短路Dijkstra求最短路栗题思想题目代码代码如下bellman-ford算法分析只能用bellman-ford来解决的题型题目完整代码 spfa求最短路spfa 算法思路明确一下松弛的概念。spfa算法文字说明&#xff1a;spfa 图解&#xff1a; 题目完整代码总结ti…

C#/WPF 清理任务栏托盘图标缓存

在我们开发Windows客户端程序时&#xff0c;往往会出现程序退出后&#xff0c;任务还保留之前程序的缓存图标。每打开关闭一次程序&#xff0c;图标会一直增加&#xff0c;导致托盘存放大量缓存图标。为了解决这个问题&#xff0c;我们可以通过下面的程序清理任务栏托盘图标缓存…

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 4-1、线条平滑曲面(原始图形)

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fr…

案例分析篇03:一篇文章搞定软考设计模式考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12601310.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

WorkPlus Meet提供高度安全的私有化会议解决方案,保护企业隐私

在企业内部沟通和机密信息传递方面&#xff0c;保护企业的隐私和保证会议质量是至关重要的。作为一款私有化会议解决方案&#xff0c;WorkPlus Meet以其卓越的性能和高度安全的特性&#xff0c;助力企业建立安全可靠的私有化会议平台。 为何选择WorkPlus Meet作为私有化会议的安…

Editor.md-编辑器

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

msfconsole中db_namp的使用方法以及如何让msf连接数据库

一、db_nmap使用方法 1.打开数据库 1.1查看数据库postgresql连接状态 systemctl status postgresql查看数据库postgresql连接状态、 1.2启动postgresql systemctl start postgresql启动postgresql 1.3初始化 msfdb init初始化 2.C段扫描(db_nmap的使用) 2.1 db_nmap -sP 192…

多维时序 | Matlab实现VMD-CNN-LSTM变分模态分解结合卷积神经网络结合长短期记忆神经网络多变量时间序列预测

多维时序 | Matlab实现VMD-CNN-LSTM变分模态分解结合卷积神经网络结合长短期记忆神经网络多变量时间序列预测 目录 多维时序 | Matlab实现VMD-CNN-LSTM变分模态分解结合卷积神经网络结合长短期记忆神经网络多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介…

wxss和css的区别

目录 1. 语法差异 2. 尺寸单位 3. 样式导入 WXSS 示例代码&#xff1a; CSS 示例代码&#xff1a; 4. 组件和属性的支持 总结 WXSS (WeiXin Style Sheets) 和 CSS (Cascading Style Sheets) 都是用于描述文档样式的语言&#xff0c;但它们在微信小程序和网页开发中有一些…

部署私有KMS服务器,并设置自动激活Windows和office

介绍 vlmcsd是一个KMS激活服务器的模拟器&#xff0c;可以在Windows Server之外的平台上部署自己的KMS服务器。它是一个开源项目&#xff0c;由Wind4开发&#xff0c;目前在Linux上运行&#xff08;包括Android、FreeBSD、Solaris、Minix、Mac OS、iOS和Windows等&#xff09;…

基于cnn的卷机神经网络的项目毕业课题实践应用(毕业选题-深度学习-卷及神经网络)

这些项目可以作为毕业课题选择&#xff0c;共计超过20个&#xff1a; 往期热门项目回顾&#xff1a; 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别…

OSI七层模型TCP四层模型横向对比

OSI 理论模型&#xff08;Open Systems Interconnection Model&#xff09;和TCP/IP模型 七层每一层对应英文 应用层&#xff08;Application Layer&#xff09; 表示层&#xff08;Presentation Layer&#xff09; 会话层&#xff08;Session Layer&#xff09; 传输层&#x…