热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

实现《魔影》音视频模块开发

1.音视频采样编码的基本原理将模拟信号转化为数字信号,隔段时间进行采样2.ffmpeg的基本情况介绍Fmpeg是领先的多媒体框架,能够解码、编码

1.音视频采样编码的基本原理

将模拟信号转化为数字信号,隔段时间进行采样
在这里插入图片描述

2.ffmpeg的基本情况


介绍

Fmpeg 是领先的多媒体框架,能够解码、编码、转码、混合、解密、流媒体、过滤和播放人类和机器创造的几乎所有东西。它支持最晦涩的古老格式,直到最尖端的格式。无论它们是由某个标准委员会、社区还是公司设计的。它还具有高度的便携性。
FFmpeg 可以在 多个平台构建环境、机器架构和配置下编译、运行,并通过测试基础设施 FATE。

FFmpeg命令行工具获取


  • 下载地址
    • 访问FFmpeg官网(http://ffmpeg.org)选择Download,选择Windows Package进入Zeranoe FFmpeg网站。
    • 注意不要直接从FFmpeg官网下载源代码。
  • 版本说明
    • Zeranoe网站中的FFmpeg分为3个版本:
      • static:只包含3个体积很大的exe文件。
      • shared:除了3个体积较小的exe文件外,还包含了dll动态库文件
      • Dev:只包含了开发用的头文件(*.h)和导入库文件(*.lib)
  • 一般使用命令行时下载Static或者Shared版本就可以了
  • 进行开发需要下载Dev版本

ffmpeg.exe的使用


  • 命令格式

    • 功能
      ffmpeg.exe用于视频的转码

    • 最简单的命令

      ffmpeg -i input.avi -b:v 640k output.ts

    • 该命令将当前文件夹下的input.avi转换为output.ts文件,并将其文件视频的码率设置为640kbps。

    • 命令格式

      ffmpeg -i (输入文件路径) -b:v (输出视频码率) (输出文件路径)

    • 命令参数

    参数说明
    -h帮助
    -i filename输入文件
    -t duration设置处理时间,格式为hh:mm:ss
    -ss duration设置起始时间,格式为hh:mm:ss
    -b:v bltrate设置视频码率
    -b:a bitrate设置音频码率
    -r fps设置帧率
    -s wxh设置分辨率,格式为WxH(用*也可以)
    -c:v codec设置视频编码器
    -c:a codec设置音频编码器
    -ar freq设置音频采样率

    如: ffmpeg -i video.mkv video.mp4 将video从MKV格式转码为MP4格式并另外保存


ffplay.exe的使用


  • 命令格式

    • 功能
      用于视频的播放

    • 最简单的命令

      ffplay input.avi

    • 该命令将播放当前文件夹下的input.avi文件。

    • 命令格式

      ffmpeg (输入文件路径)

    • 命令参数

    快捷键说明
    q,ESC退出
    p,空格暂停
    鼠标右键屏幕跳转到指定位置

解封装


  • av+register_all():注册所有组件

  • avformat_network_init()

  • avformat_open_input(…):打开输入视频文件

    • 确保av_register_all、avformat_network_init已经停用
    • AVFormatContext **ps
    • const char *url
    • AVInputFormat *fmt
    • AVDIctionary **options
  • avformat_find_stream_info(…):获取视频文件信息

  • avcodec_find_decoder():查找解码器

  • avcodec_open2():打开解码器

  • av_find_best_stream(…)

  • AVFormatContext (封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息)

    • AVIOContext *pd;char filename[1024];
    • iformat //输入视频的AVInputFormat
    • unsigned int nb_streams; //输入视频的AVStream
    • AVStream **streams; //输入视频的AVStream []数组
    • int64_t duration; //AV_TIME_BASE 输入视频的时长(以微秒为单位)
    • int64_t bit_rate; //输入视频码率
    • void avformat_close_input(AVFormatContent **s); //关闭输入视频文件,释放空间
  • AVInputFormat (每种封装格式(例如FLV,MKV,MP4,AVI)对应一个结构体)

    • name:封装格式名称
    • long_name:封装格式的长名称
    • extensions:封装格式的扩展名
    • id:封装格式ID
    • 一些封装格式处理的接口函数
  • AVStream (视频文件中每个视频(音频)流对应一个结构体)

    • AVCodecContext *codec; //过时了
    • id //序号
    • AVRational time_base; //分数表示,减少精度损失
    • int64_t duration; //毫秒 duration (time_base,num/(double)time_base.den) 1000毫秒
    • int64_t nb_frames;
    • AVRational avg_frame_rate;
    • AVCodecParameters *codecpar:(音视频参数)用于替代过时的1
      • AVBufferRef *buff; //删除的时候-1
      • int64_t pts; //pts * (num/den) 显示时间戳
      • int64_t dts; //解码时间戳
      • unit8_t *data; //压缩编码数据
      • int size; //压缩编码数据大小
      • stream_index //所属的AVStream
      • AVPacket *av_packet_alloc(void); //创建并初始化,申请了堆上的空间,需要自己释放
      • AVPacket *av_packet_clone(const AVPacket *src); //创建和并用计数
      • int av_packet_ref(AVPacket *dst,const AVPacket *src);
      • av_packet_unred(AVPacket *pkt);
      • void av_packet_free(AVPacket **pkt); //清空对象并减引用计数
      • void av_init_packet(AVPacket *pkt); //默认值
      • int av_packet_from_data(AVPacket *pkt,unit7_t *data,int size);
      • int av_copy_packet(AVPacket *dst,const AVPacket *src); ///attribute_deprecated用clone函数代替了
  • av_read_frame(…):从输入文件读取一帧压缩数据

    • AVFormatContext *s;
    • AVPacket *pkt; //不能传null
    • return 0 if OK, <0 on error or end of file
  • avcodec_decode_video2()&#xff1a;解码一帧压缩数据

  • avcodec_close()&#xff1a;关闭解码器


找寻


3.PCM过程的一些基本参数

PCM音频数据

4.视频的封装格式及播放的基本流程

视频播放器原理

  • 封装格式(MP4,RMVB,TS,FLV,AVI)
  • 视频编码数据(H.264.MPEG2,VC-1)
  • 音频编码数据(AAC,MP3,AC-3)
  • 视频像素数据(YUV420P,RGB)
  • 音频采样数据(PCM)

播放视频流程

在这里插入图片描述
可以使用软件mediainfo进行读取。

5. ffmpeg的解码大致流程

在这里插入图片描述

FFmpeg解码的流程图如下所示

在这里插入图片描述

6.ffmpeg程序的环境配置

配置ffmpeg所依赖的文件(此处是VS的配置&#xff0c;Qt Creator单独配置)&#xff1a;

  • C&#43;&#43; -> 常规 -> 附加包含目录(ffmpeg的include目录)
  • 链接器 -> 附加库目录(debug下面的x64)
  • 调试->工作目录(代码中包含的文件(资料文件&#xff0c;视频文件)所需要的路径)
  • 针对C语言需要多添加一句&#xff1a;

extern "C"{#include "libacformat/avformat.h"
}

  • 代码包含或者配置"附加依赖项"(包含lib库)

7.ffmpeg编写解码程序


第一部分

#include
#include
extern "C" {#include "libacformat/avformat.h"
}#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")static double FractionToDouble(AVRational fraction)//AVRational为分数表示&#xff0c;其目的为避免精度损失&#xff0c;分数表示为分子除以分母
{return fraction.den &#61;&#61; 0?0:(double)fraction.num/(double)fraction.den;
}int main(int argc,char *argv[])
{QCoreApplication a(argc,argv);const char* path &#61; "test.mp4";//初始化封装库av_register_all();//打开输入视频文件AVFormatContext *avfc &#61; NULL;int ret &#61; avformat_open_input(&avfc,path,NULL,NULL); //传二级指针一般是对指针进行赋值的时候if(ret !&#61; 0){qDebug()<<"OPen"<<path<<"failed!";exit(-1);}//获取流信息ret &#61; avformat_find_stream_info(avfc,NULL);if(ret < 0){qDebug()<<"avformat_find_stream_info_failed!";exit(-1);}//总时长-秒数qDebug()<<(avfc->duration / AV_TIME_BASE);//avfc->streamsqDebug()<<"streams number is:"<<avfc->nb_streams;for(int i &#61; 0; i < avfc->nb->streams;i&#43;&#43;){qDebug()<<"i is "<<i;AVStream* as &#61; avfc->streams[i];qDebug()<<as->codecpar->codec_id; //AV_CODEC_ID_H264(解码)qDebug()<<as->codecpar->format;qDebug();//音频 AVMEDIA_TYPE_AUDIOif(as->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_AUDIO){qDebug()<<i<<"audio info";qDebug()<<"sample_rate&#61;"<<as->codecpar->sample_rate;qDebug()<<"Channels&#61;"<<as->codecpar->channels;}//视频 AVMEDIA_TYPE_VIDEOelse if(as->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO){qDebug()<<i<<"video info";qDebug()<<"width&#61;"<<as->codecpar->width;qDebug()<<"height&#61;"<<as->codecpar->height;//帧率fpsqDebug()<<"video fps&#61;"<<FractionToDouble(as->avg_frame_rate);}}return a.exec();
}

第二部分

#include
#include
extern "C" {#include "libacformat/avformat.h"#include "libavcodec/avcodec.h" //解码
}#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")static double FractionToDouble(AVRational fraction)
{return fraction.den &#61;&#61; 0?0:(double)fraction.num/(double)fraction.den;
}int main(int argc,char *argv[])
{QCoreApplication a(argc,argv);const char* path &#61; "test.mp4";av_register_all();//初始化解码器avcodec_register_all();//音视频索引&#xff0c;读取时可以区别音视频int videoStream &#61; 0; //int audioStream &#61; 1; //AVFormatContext *avfc &#61; NULL;int ret &#61; avformat_open_input(&avfc,path,NULL,NULL);if(ret !&#61; 0){qDebug()<<"OPen"<<path<<"failed!";exit(-1);}ret &#61; avformat_find_stream_info(avfc,NULL);if(ret < 0){qDebug()<<"avformat_find_stream_info_failed!";exit(-1);}qDebug()<<(avfc->duration / AV_TIME_BASE);//avfc->streamsqDebug()<<"streams number is:"<<avfc->nb_streams;for(int i &#61; 0; i < avfc->nb->streams;i&#43;&#43;){qDebug()<<"i is "<<i;AVStream* as &#61; avfc->streams[i];qDebug()<<as->codecpar->codec_id;qDebug()<<as->codecpar->format;qDebug();if(as->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_AUDIO){audioStream &#61; i; //qDebug()<<"sample_rate&#61;"<<as->codecpar->sample_rate;qDebug()<<"Channels&#61;"<<as->codecpar->channels;}else if(as->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO){videoStream &#61; i; //qDebug()<<"width&#61;"<<as->codecpar->width;qDebug()<<"height&#61;"<<as->codecpar->height;qDebug()<<"video fps&#61;"<<FractionToDouble(as->avg_frame_rate);}}//找到视频解码器&#xff0c;创建并打开解码器AVCodec* vcodec &#61; avcodec_find_decoder(avfc->streams[videoStream]->codecpar->code_id);if (vcodec){qDebug()<<"video Can&#39;t find the video codec";}//上下文AVCodecCOntext* vc &#61; avcodec_alloc_context3(vcodec);//参数ret &#61; avcodec_parameters_to_context(vc,avfc->streams[videoStream]->codecpar);if (ret < 0){qDebug()<<"video avcodec_parameters_to_context failed";}//8线程同时解码vc->thread_count &#61; 8;avcodec_open2(vc,NULL,NULL);if (ret < 0){qDebug()<<"video avcodec_open2 failed";}//找到音频解码器&#xff0c;创建并打开解码器AVCodec* acodec &#61; avcodec_find_decoder(avfc->streams[audiooStream]->codecpar->code_id);if (acodec){qDebug()<<"audio Can&#39;t find the video codec";}//上下文AVCodecCOntext* ac &#61; avcodec_alloc_context3(acodec);//参数ret &#61; avcodec_parameters_to_context(ac,avfc->streams[audiooStream]->codecpar);if (ret < 0){qDebug()<<"audio avcodec_parameters_to_context failed";}//8线程同时解码ac->thread_count &#61; 8;avcodec_open2(ac,NULL,NULL);if (ret < 0){qDebug()<<"audio accodec_open2 failed";}//Packet,FrameAVPacket* pkt &#61; av_packet_alloc(); //using av_packet_free()AVFrame* frame &#61; av_frame_alloc(); //using av_frame_free()ret &#61; 0;while(ret >&#61; 0){ret &#61; av_read_frame(avfc,pkt); //一帧帧的读qDebug()<<"pkt->size&#61;"<<pkt->size;qDebug()<<"pkt->pts&#61;"<<pkt->pts;qDebug()<<"pkt->dts&#61;"<<pkt->dts;//完成解码操作AVCodecContext* cc &#61; NULL;if(pkt->stream_index &#61;&#61; videoStream){qDebug()<<"视频数据";cc &#61; vc;}else if(pkt->stream_index &#61;&#61; audeoStream){qDebug()<<"音频数据";cc &#61; ac;}int ret2 &#61; avcodec_send_packet(cc,pkt);//以frame形式输出av_packet_unref(pkt);//引用计数-1if(ret2 !&#61; 0){qDebug<<"Send packet failed";}//接受framewhile(true){//有可能多处接受decode发过来的frameint ret3 &#61; avcodec_receive_frame(cc,frame);if(ret3 !&#61; 0){break;}qDebug<<"recv frame"<<frame->format<<" "<<frame->linesize[0];}}//释放资源av_frame_free(&frame);av_packet_free(&pkt);if(avfc){avformat_close_input(&avfc);}avfc &#61; NULL;return a.exec();
}


推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文探讨了Hive中内部表和外部表的区别及其在HDFS上的路径映射,详细解释了两者的创建、加载及删除操作,并提供了查看表详细信息的方法。通过对比这两种表类型,帮助读者理解如何更好地管理和保护数据。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • PHP 5.5.0rc1 发布:深入解析 Zend OPcache
    2013年5月9日,PHP官方发布了PHP 5.5.0rc1和PHP 5.4.15正式版,这两个版本均支持64位环境。本文将详细介绍Zend OPcache的功能及其在Windows环境下的配置与测试。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入理解Tornado模板系统
    本文详细介绍了Tornado框架中模板系统的使用方法。Tornado自带的轻量级、高效且灵活的模板语言位于tornado.template模块,支持嵌入Python代码片段,帮助开发者快速构建动态网页。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
author-avatar
mobiledu2502922617
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有