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格式的说明。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

异常处理【C++提升】(基本思想,重要概念,异常处理的函数机制、异常机制,栈解旋......你想要的全都有)

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 本文所在专栏&#xff1a; C系列语法知识_Stark、的博客-CSDN博客 座右铭&#xff1a;梦想是一盏明灯&#xff0c;照亮我们前行的路&#xff0c;无论风雨多大&#xff0c;我们都要坚持不懈。 异…

828华为云征文|华为云Flexus云服务器X实例搭建部署H5美妆护肤分销商城、前端uniapp

准备国庆之际&#xff0c;客户要搭个 H5 商城系统&#xff0c;这系统好不容易开发好啦&#xff0c;就差选个合适的服务器上线。那可真是挑花了眼&#xff0c;不知道哪款性价比高呀&#xff01;就像在琳琅满目的选择前。最终慧眼识珠&#xff0c;选择了华为云 Flexus X。至于为什…

redis高级篇 抢红包案例的设计以及分布式锁

一 抢红包案例 1.1 抢红包 二倍均值算法&#xff1a; M为剩余金额&#xff1b;N为剩余人数&#xff0c;公式如下&#xff1a; 每次抢到金额随机区间&#xff08;0&#xff0c;&#xff08;M/N&#xff09;*2&#xff09; 这个公式&#xff0c;保证了每次获取的金额平均值…

TX-LCN框架 分布式事务

一、三种事务模式 1&#xff09;LCN 基于XA协议&#xff0c;事务提交或回滚的操作由事务管理服务器统一告诉它管理的多个项目&#xff0c;也就是说在A事务&#xff0c;B事务的事务提交操作或回滚操作都是在同一时刻发生&#xff0c;并且要么都提交&#xff0c;要么都回滚。 LCN…

低代码可视化-UniApp二维码可视化-代码生成器

市面上提供了各种各样的二维码组件&#xff0c;做了一简单的uniapp二维码组件&#xff0c;二维码实现依赖davidshimjs/qrcodejs。 组件特点 跨浏览器支持&#xff1a;利用Canvas元素实现二维码的跨浏览器兼容性&#xff0c;兼容微信小程序、h5、app。 无依赖性&#xff1a;QR…

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(一).创建基础表

一. 使用工具和命令 1.1 使用的工具 Navicat Premium 17 &#xff1a;“Navicat”是一套可创建多个连接的数据库管理工具。 MySQL版本8.0.39 。 1.2 使用的命令 Navicat中使用的命令 命令命令解释SHOW DATABASES&#xff1b;展示所有的数据库CREATE DATABASE 数据库名称; 创…

震动传感器介绍及实战

目录 前言 震动传感器 1.震动传感器配图 2.震动传感器原理图 3.震动传感器使用 1-震动传感器的意义 2-震动传感器的应用场景 3- SW-18010P震动传感器使用方法 震动传感器控制灯 操作 增加延时 使用SPC-ISP生成演示函数 总结 前言 我们上节已经简单了解了LED的使用…

【机器学习】音乐生成——AI如何创作个性化音乐与配乐

我的主页&#xff1a;2的n次方_ 音乐是人类文化的重要组成部分&#xff0c;它具有极强的情感表达和艺术价值。近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI已经能够自动生成音乐&#xff0c;甚至根据用户需求创作个性化配乐。AI生成音乐的应用场景广泛&…

redis中的数据类型(Set与ZSet)

&#xff08;一&#xff09;set set在我们目前有两个意思&#xff0c;首先就是这里使用的集合&#xff0c;第二个是我们的set和get方法 因为set是一个集合&#xff0c;所以他具有集合的一些特点&#xff1a; 1.集合中的元素无序 2.集合中的元素是不可重复的 3.集合间是可…

5G NR物理信号

文章目录 NR 物理信号与LTE的区别上行参考信号DMRS (UL)SRSPT-RS(UL) 下行参考信号DMRS(DL)PT-RS(DL)CSI-RSPSSSSS NR 物理信号与LTE的区别 用SSS、CSI-RS和DMRS 取代了CRS信号。下行业务信道采用TM1波束赋形传输模式。基于SSB 或者CSI-RS进行RSRP和SINR测量。基于DMRS 进行共…

【Mybatis篇】Mybatis的关联映射详细代码带练 (多对多查询、Mybatis缓存机制)

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】,【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;一.关联映射概述 &#x1f6a…

2024.9.29 问卷数据分析

最近拿到了一份受众回访的问卷数据&#xff0c;排到的任务是对它进行数据探索。 其实对于问卷数据的处理我只在参加正大杯那次做过&#xff08;正大杯拿了校三&#xff09;&#xff0c;可见这个处理水平还有待提高&#xff08;当然是各种原因促成的结果&#xff09;&#xff0…

17 链表——21. 合并两个有序链表 ★

17 链表 21. 合并两个有序链表 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4] 算法设计: 合并两个有序链表,并保持有序性,可以采用迭代法和递归法两种…

卸载WSL(Ubuntu),卸载linux

禁用 WSL 功能 打开 Windows 功能&#xff1a; 按下 Windows R 打开运行对话框&#xff0c;输入 optionalfeatures&#xff0c;然后按回车。 禁用 WSL&#xff1a; 在弹出的 Windows 功能窗口中&#xff0c;找到 适用于 Linux 的 Windows 子系统&#xff08;Windows Subsystem…

Windows环境 源码编译 FFmpeg

记录一下windows环境纯代码编译ffmeg的过程&#xff01; 目录 一、安装MSYS2 1.下载安装 2.配置 3.修改源 4.测试与更新 二、安装其他必要工具 1.安装MinGW-w64 2.安装git 3..安装make等工具 4.编译前的其他准备工作 ①.重命名link.exe ②.下载和安装YASM ③.安装…

Docker 从安装到实战

Docker 是一个开源的平台&#xff0c;用于自动化应用程序的部署、扩展和管理。它利用操作系统级别的虚拟化&#xff0c;将应用程序及其依赖项封装在称为容器的轻量级、可移植的单元中。以下是 Docker 的一些关键特点&#xff1a; 容器化&#xff1a;Docker 容器可以在任何支持 …

用CSS创造三角形案例

6.3.2 用CSS创造三角形 用div来创建&#xff0c;角上是平分的&#xff0c;所以要是内部宽高为0&#xff0c;其他边透明&#xff0c;正好是三角形。 代码 div {border: 12px solid;width: 0;height: 0;border-color: transparent red transparent transparent; } 与伪元素aft…

vscode+stfp插件,实现远程自动同步文件代码

概述 远程同步代码&#xff0c;将本地代码实时保存到同一局域网内的另一台电脑&#xff08;linux系统&#xff09;&#xff0c;这里的本地代码也可以是远程服务上的代码&#xff0c;即从一个远程ip同步到另一台远程ip服务器。 工具 vscode&#xff0c;SFTP插件 安装 vscod…

【重学 MySQL】五十、添加数据

【重学 MySQL】五十、添加数据 使用INSERT INTO语句添加数据基本语法示例插入多行数据注意事项 使用LOAD DATA INFILE语句批量添加数据其他插入数据的方式注意事项 在MySQL中&#xff0c;添加数据是数据库操作中的基本操作之一。 使用INSERT INTO语句添加数据 使用 INSERT IN…

突发!Meta重磅发布Movie Gen入局视频生成赛道!

引言 Meta于2024年10月4日首次推出 Meta Movie Gen&#xff0c;号称是迄今为止最先进的媒体基础模型。Movie Gen 由 Meta 的 AI 研究团队开发&#xff0c;在一系列功能上获取最先进的效果&#xff0c;包括&#xff1a;文生视频、创建个性化视频、精准的视频编辑和音频创作。 …