当前位置: 首页 > news >正文

ffmpeg取rtsp流音频数据保存声音为wav文件

本来不是什么难搞的问题,代码写完了,音频流信息中的详细信息,具体代码表现为

format_ctx->streams[audio_stream_index]->codecpar是空指针。

这个查了一圈也没人给出正确答案,实际上是由于我自己编译的ffmpeg时候,开启的选项的导致的。把音频解码器相关的给禁掉了。重新开启相关编译选项,编译ffmpeg后,一切正常。

具体的选项为:

ffmpeg 交叉编译./configure --prefix=../arm-ffmpegbuild \
--enable-shared \
--enable-libmp3lame \--enable-libx264 \--enable-gpl \--disable-asm \--enable-version3 \--enable-libmp3lame \--enable-libx264 \--enable-libvpx \--enable-nonfree \--cross-prefix=aarch64-linux- \--target-os=linux \--extra-cflags="-I /opt/ffmpeg_test_make/lame-3.100/lamebuild/include" \--extra-ldflags="-L /opt/ffmpeg_test_make/lame-3.100/lamebuild/lib" \--enable-cross-compile \--enable-small \--arch=arm64 \--enable-decoder=h264 \--enable-parser=h264 \--enable-demuxer=rtsp \--extra-ldflags="-L ../x264build/lib" \--extra-cflags="-I ../x264build/include"lame交叉编译./configure \--host=aarch64-linux \--prefix=/opt/ffmpeg_test_make/lame-3.100/lamebuild \cc=aarch64-linux-gcc 

话不多说上代码:


bool FfpDecoderWav::dump_wav(std::string rtsp_url, std::string file_path) {AVDictionary *format_options = NULL;av_dict_set(&format_options, "rtsp_transport", "tcp", 0); // 以tcp的方式打开,av_register_all();avformat_network_init();// 打开 RTSP 流int reconnect_times = 3;AVFormatContext *format_ctx = NULL;bool online = false;while (reconnect_times-- > 0) {if (format_ctx != NULL) {avformat_close_input(&format_ctx);format_ctx = NULL;}format_ctx = avformat_alloc_context();if (avformat_open_input(&format_ctx, rtsp_url.c_str(), NULL, &format_options) != 0) {Logger::error("open rtsp url:{} faile", rtsp_url);// std::this_thread::sleep_for(std::chrono::milliseconds(500));usleep(100000);} else {online = true;break;}}av_dict_free(&format_options); // 释放 format_optionsif (!online) {return false;}Logger::info("open rtsp url:{} for wav success", rtsp_url);// 查找音频流int audio_stream_index = -1;if (avformat_find_stream_info(format_ctx, NULL) < 0) {Logger::info("can not avformat_find_stream_info url:{}", rtsp_url);return false;}AVCodec *codec = NULL;audio_stream_index = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);std::cout << "codec name :" << codec->name << std::endl;std::cout << "codec long_name :" << codec->long_name << std::endl;std::cout << "codec AVMediaType :" << (int)codec->type << std::endl;std::cout << "codec AVCodecID :" << (int)codec->id << std::endl;if (audio_stream_index < 0 || codec == NULL) {Logger::info("can not find sound stream rtsp url:{}", rtsp_url);return false;}Logger::info("find sound stream success index:{}", audio_stream_index);av_dump_format(format_ctx, 0, rtsp_url.c_str(), 0);bool had_audio_code = true;SwrContext *swr_ctx = NULL;AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);if (format_ctx->streams[audio_stream_index]->codecpar) {Logger::info("avcodec_alloc_context3 success channels={}", codec_ctx->channels);Logger::info("avcodec_alloc_context3 success sample_rate={}", codec_ctx->sample_rate);// std::cout << "had codecpar inf" << std::endl;// printf("had codecpar inf\n");avcodec_parameters_to_context(codec_ctx, format_ctx->streams[audio_stream_index]->codecpar);if (avcodec_open2(codec_ctx, codec, NULL) < 0) {Logger::info("avcodec_open2 error rtsp url:{}", rtsp_url);return false;}Logger::info("avcodec_open2 success channels={}", codec_ctx->channels);Logger::info("avcodec_open2 success sample_rate={}", codec_ctx->sample_rate);// 创建重采样上下文swr_ctx = swr_alloc_set_opts(NULL, NUM_CHANNELS, AV_SAMPLE_FMT_S16, SAMPLE_RATE, codec_ctx->channels,codec_ctx->sample_fmt, codec_ctx->sample_rate, 0, NULL);Logger::info("swr_alloc_set_opts success");if (!swr_ctx || swr_init(swr_ctx) < 0) {// Logger::info("swr_init error rtsp url:{}", rtsp_url);return false;}} else {printf("cdecpar is nullodecpar is nullodecpar is nullodecpar is null\n");std::cout << "codecpar is null" << std::endl;had_audio_code = false;}// 创建输出 WAV 文件std::ofstream wav_file(file_path.c_str(), std::ios::binary);if (!wav_file) {// Logger::info("fopen local_path save wav failed path:{}", file_path);return false;}// Logger::info("open wav_file success");//  写入 WAV 文件头WAVHeader wav_header;unsigned int file_size = sizeof(wav_header);// Logger::info("wav_header size:{}", file_size);wav_file.write((const char *)&wav_header, file_size);time_t start_time = time(NULL);AVPacket packet;int ret = 0;int count = 1000;while (true) {if (ret = av_read_frame(format_ctx, &packet) < 0) {// Logger::info("av_read_frame failed: {}", ret);break;}time_t current_time = time(NULL);time_t duration = current_time - start_time;if (duration > 60) {// Logger::info("save sound end by 20 s time");break;}if (packet.stream_index == audio_stream_index) {if (!had_audio_code) {wav_file.write((char *)packet.data, packet.size);std::cout << "write sws data codecpar inf insfsjfjaslkjfas" << std::endl;printf(" wav_file.write((char *)packet.data, packet.size);\n");continue;}AVFrame *frame = av_frame_alloc();if (avcodec_send_packet(codec_ctx, &packet) >= 0 && avcodec_receive_frame(codec_ctx, frame) >= 0) {uint8_t *out_buffer[NUM_CHANNELS];int out_samples = 0;int out_size = 0;for (int i = 0; i < NUM_CHANNELS; i++) {out_buffer[i] = (uint8_t *)malloc(frame->nb_samples * 2 * sizeof(uint8_t));}out_samples = swr_convert(swr_ctx, out_buffer, frame->nb_samples, (const uint8_t **)frame->data,frame->nb_samples);out_size = out_samples * NUM_CHANNELS * 2;wav_file.write(reinterpret_cast<char *>(out_buffer[0]), out_size);// std::cout << "write sws data codecpar inf" << std::endl;// printf(" wav_file.write(reinterpret_cast<char *>(out_buffer[0]), out_siz22;\n");for (int i = 0; i < NUM_CHANNELS; i++) {free(out_buffer[i]);}}av_frame_free(&frame);}av_packet_unref(&packet);}// 更新 WAV 文件头中的数据大小uint32_t subchunk2Size = static_cast<unsigned int>(wav_file.tellp()) - 44;uint32_t chunkSize = subchunk2Size + 36;wav_file.seekp(4, std::ios::beg);wav_file.write(reinterpret_cast<char *>(&chunkSize), 4);wav_file.seekp(40, std::ios::beg);wav_file.write(reinterpret_cast<char *>(&subchunk2Size), 4);// 关闭文件wav_file.close();// 释放资源avcodec_close(codec_ctx);avcodec_free_context(&codec_ctx);avformat_close_input(&format_ctx);swr_free(&swr_ctx);// Logger::info("save local_path  wav success path:{}", file_path);return true;
}

wav格式的数据头文件:

struct WAVHeader {char chunkID[4] = {'R', 'I', 'F', 'F'};uint32_t chunkSize = 0;char format[4] = {'W', 'A', 'V', 'E'};char subchunk1ID[4] = {'f', 'm', 't', ' '};uint32_t subchunk1Size = 16;uint16_t audioFormat = 1;uint16_t numChannels = NUM_CHANNELS;uint32_t sampleRate = SAMPLE_RATE;uint32_t byteRate = SAMPLE_RATE * NUM_CHANNELS * 16 / 8;uint16_t blockAlign = 4;uint16_t bitsPerSample = 16;char subchunk2ID[4] = {'d', 'a', 't', 'a'};uint32_t subchunk2Size = 4;
};

最后,就是wav注意的地方,一共是两个值:

chunkSize 和subchunk2Size

// 更新 WAV 文件头中的数据大小

也就是说:subchunk2Size是出去wav文件头部数据意外的数据长度。

即文件总长度减去头部长度44个字节。

chunkSize=subchunk2Size+36

具体为什么,可以查看wav格式的说明。

相关文章:

ffmpeg取rtsp流音频数据保存声音为wav文件

本来不是什么难搞的问题&#xff0c;代码写完了&#xff0c;音频流信息中的详细信息&#xff0c;具体代码表现为 format_ctx->streams[audio_stream_index]->codecpar是空指针。 这个查了一圈也没人给出正确答案&#xff0c;实际上是由于我自己编译的ffmpeg时候&#x…...

《数字图像处理基础》学习01-数字图像处理的相关基础知识

这篇文章只是对数字图像处理的相关基础知识有个大概的了解&#xff0c;之后的文章会接着补充和扩展。 目录 一&#xff0c;图像的基本概念 1&#xff0c;图像 2&#xff0c;图像的分类 1&#xff09;物理图像 2&#xff09;虚拟图像 二&#xff0c;数字图像处理 三&…...

C#-泛型学习笔记

C#泛型——约束|协变|逆变 1、泛型使用 在生命时可以使用<>&#xff0c;可以写一个标识符代替一些数据类型&#xff0c;在声明时给出明确定义。 非常强大&#xff0c;因此需要约束。 2、泛型约束 where T: struct//值类型约束&#xff0c;要求泛型必须为基本数据类型…...

Java第二阶段---11封装---第四节 static 修饰符

1.static 修饰符应用范围 static修饰符只能用来修饰类中定义的成员变量、成员方法、代码块以及内部类(内部类有专门章节进行讲解)。 2.static 修饰成员变量 static 修饰的成员变量称之为类变量。属于该类所有成员共享。 示例 package cn.lyxq.test04;public class Chinese…...

【C/C++】错题记录(五)

题目一 题目二 在 16 位机器上&#xff0c;通常以 2 字节为边界对齐。 首先看 char a&#xff0c;它占用 1 个字节。接着是 int b&#xff0c;占用 2 个字节。由于要满足边界对齐&#xff0c;在 char a后面会填充 1 个字节&#xff0c;使得 int b从 2 字节边界开始存储。最后是…...

关系数据库标准语言SQL(11,12)

目录 带有EXISTS谓词的子查询 exists谓词 例子 not exists谓词 例子 不同形式的查询间的替换 用EXISTS/NOT EXISTS实现全称量词 用EXISTS/NOT EXISTS:实现逻辑蕴涵 集合查询 并操作UNION 交操作INTERSECT 差操作EXCEPT 基于派生表的查询 select语句的基本格式 带有…...

Oracle 11g RAC 节点异常重启问题分析

一、背景 在国庆期间巡检的时候&#xff0c;发现数据库alert日志中出现了异常重启的信息&#xff0c;当即对该报错进行分析处理。 二、处理过程 &#xff08;1&#xff09;数据库告警日志分析 node1 alert&#xff1a; Sat Oct 05 13:05:14 2024 Thread 1 advanced to log …...

vscode 中显示 pnpm : 无法加载文件 C:\Users\AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本

vscode中运行pnpm报错 pnpm : 无法加载文件 C:\Users\AppData\Roaming\npm\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本 解决办法如下 1、用 get-ExecutionPolicy 命令在vscode终端查询状态 如果返回的是 Restricted &#xff0c;则说明是禁止的 2、用 set-ExecutionPolic…...

C嘎嘎入门篇:类和对象番外(时间类)

前文&#xff1a; 小编在前文讲述了类和对象的一部分内容&#xff0c;其中小编讲述过运算符重载这个概念以及一个时间类&#xff0c;当时小编讲的没有那么细致&#xff0c;下面小编将会讲述时间类来帮助各位读者朋友更好的去理解运算符重载&#xff0c;那么&#xff0c;代码时刻…...

Spring Boot项目实战教程:快速构建Web应用与RESTful API

目录 一、Spring Boot简介1、Spring Boot的定义2、Spring Boot的优势&#xff08;1&#xff09;快速开发&#xff08;2&#xff09;自动配置&#xff08;3&#xff09;微服务支持&#xff08;4&#xff09;无代码生成和XML配置&#xff08;5&#xff09;独立运行&#xff08;6&…...

OpenAI 开发者大会!实时语音功能有API了,GPT-4o支持多模态微调,上下文cache功能上线

家人们&#xff01;十一假期第1天&#xff0c; OpenAI一年一度的开发者大会又来了惹&#xff01;今年的开发者大会分成三部分分别在美国、英国、新加坡三个地点举办&#xff0c;刚刚结束的是第一场。 去年的OpenAI开发者大会公布了GPT-4 Turbo和GPTs&#xff0c;今年没有大更新…...

解决ros2 rviz Fixed Frame No TF data问题

新建一个终端&#xff0c;然后输入 &#xff1a;map后的数字可以任意&#xff0c;100也可以。注意map与框架名称一致。 rosrun tf2_ros static_transform_publisher 0.0 0.0 0.0 0.0 0.0 0.0 map 5...

Python数据分析篇--NumPy--进阶

人有一种天生的、难以遏制的欲望&#xff0c;那就是在理解之前就评判。 -- 米兰昆德拉 多维数组 1. 一维数组只有行&#xff0c;二维数组相比一维数组多了列这个维度&#xff0c;而三维数组则类似多个二维数组堆叠在一起&#xff0c;形如一个立方体。 二维数组的创建 1. 二…...

基于Arduino的宠物食物分配器

创作本文的初衷是本人的一个养宠物的梦想&#xff08;因为家里人对宠物过敏&#xff0c;因此养宠物的action一直没有落实&#xff09;&#xff0c;但是梦想总是要有的哈哈哈哈哈。上周正好是和一个很好的朋友见面&#xff0c;聊到了养宠物的事情&#xff0c;她大概是讲到了喂宠…...

make和Makefile

make是一个命令工具&#xff0c;用于读取并执行名为Makefile&#xff08;makefile&#xff09;的文件中定义的规则。 Makefile是一个文本文件&#xff0c;它告诉make哪些文件依赖于其他文件&#xff0c;以及如何从这些依赖项生成最终的目标文件。 我们先简单看一下使用make的…...

【数学分析笔记】第4章第4节 复合函数求导法则及其应用(2)

4. 微分 4.4 复合函数求导法则及其应用 【例4.4.3】 y e 1 cos ⁡ x ye^{\sqrt{1\cos x}} ye1cosx ​&#xff0c;求 y ′ y y′ 【解】 y ′ e 1 cos ⁡ x ⋅ 1 2 1 cos ⁡ x ⋅ ( − sin ⁡ x ) − sin ⁡ x 2 1 cos ⁡ x e 1 cos ⁡ x ye^{\sqrt{1\cos x}}\cdot\f…...

【预备理论知识——2】深度学习:线性代数概述

简单地说&#xff0c;机器学习就是做出预测。 线性代数 线性代数是数学的一个分支&#xff0c;主要研究向量空间、线性方程组、矩阵理论、线性变换、特征值和特征向量、内积空间等概念。它是现代数学的基础之一&#xff0c;并且在物理学、工程学、计算机科学、经济学等领域有着…...

【目标检测】yolo的三种数据集格式

目标检测中数据集格式之间的相互转换--coco、voc、yolohttps://zhuanlan.zhihu.com/p/461488682?utm_mediumsocial&utm_psn1825483604463071232&utm_sourcewechat_session【目标检测】yolo的三种数据集格式https://zhuanlan.zhihu.com/p/525950939?utm_mediumsocial&…...

数据分析案例-机器学习工程师薪资数据可视化分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…...

Django连接Dify、ChatGPT4o并计算tokens数量方法

通过Dify可以连接很多模型国内、国外的都可以进行选择可以到Dify里创建一个空白应用&#xff0c;然后点击进入就可以看到API了api_url "http://192.168.15.131/v1/chat-messages" api_key "app-UtzTpVNwpTLUcGvRNnnK9QNY" headers {"Authorization…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

Python爬虫实战:研究Restkit库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...