FastASR+FFmpeg(音视频开发+语音识别)(二)

简介: FastASR+FFmpeg(音视频开发+语音识别)(二)

二、视频中提取音频  

1.FFmpeg 

通过命令行

ffmpeg -i 视频文件路径 -vn 音频文件全路径 -hide_banner

参数说明:

-vn 从视频中提取音频

-ab 指定编码比特率(一些常见的比特率 96k、128k、192k、256k、320k)

-ar 采样率(22050、441000、48000)

-ac 声道数

-f 音频格式(通常会自动识别)

示例:

通过提供的API
bool AVInterface::extractAudio(const char* src, const char* dstDir)
{
  if (NULL == src || NULL == dstDir)
  {
    printf("Ffmpeg::extractAudio[ERROR]::无效参数,请检查文件路径是否正确\n");
    return false;
  }
  int ret = 0;
  // 预存原文件路径
  const char* src_fileName = src;
  // 1.获取媒体文件的全局上下文信息
  // 1.1 定义 AVFormatContext 容器
  AVFormatContext* pFormatCtx = NULL;      // AVFormatContext描述了一个媒体文件或者媒体流构成的基本信息
  pFormatCtx = avformat_alloc_context();   // 为 pFormatCtx 申请内存
  // 1.2 打开媒体文件,并且读取媒体文件的头信息放入pFormatCtx中
  ret = avformat_open_input(&pFormatCtx, src_fileName, NULL, NULL);
  if (ret < 0)
  {
    printf("Ffmpeg::extractAudio[ERROR]::打开媒体流文件失败\n");
    return false;
  }
  // 2.探测流出信息
  // 2.1 探寻文件中是否存在信息流,如果存在则将多媒体文件信息流放到pFormatCtx
  ret = avformat_find_stream_info(pFormatCtx, NULL);
  if (ret < 0)
  {
    printf("Ffmpeg::extractAudio[ERROR]::文件中不存在信息流\n");
    return false;
  }
  av_dump_format(pFormatCtx, 0, src_fileName, 0);    // 打印封装格式和流信息
  // 2.2 查找文件信息流中是否存在音频流(我们只需要提取音频),并获取到音频流在信息流中的索引
  int audio_stream_index = -1;
  audio_stream_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
  if (-1 == audio_stream_index)
  {
    printf("Ffmpeg::extractAudio[ERROR]::文件中不存在音频流\n");
    return false;
  }
  // 3.输出容器的定义
  AVFormatContext* pFormatCtx_out = NULL;    // 输出格式的上下文信息  
  const AVOutputFormat*  pFormatOut = NULL;        // 输出的封装格式
  AVPacket packet;                         
  // 输出文件路径
  char szFilename[256] = { 0 };
  snprintf(szFilename, sizeof(szFilename), "%s/ffmpeg-music.aac", dstDir);
  // 3.1 初始化容器
  // 初始化一些基础的信息
  av_init_packet(&packet);                 
  // 给 pFormatCtx_out 动态分配内存,并且会根据文件名初始化一些基础信息
  avformat_alloc_output_context2(&pFormatCtx_out, NULL, NULL, szFilename);  
  // 得到封装格式 AAC
  pFormatOut = pFormatCtx_out->oformat;
  // 4.读取音频流,并且将输入流的格式拷贝到输出流的格式中
  for (int i = 0; i < pFormatCtx->nb_streams; ++i)   // nb_streams 流的个数
  {
    // 流的结构体,封存了一些流相关的信息
    AVStream* out_stream = NULL;               // 输出流
    AVStream* in_stream  = pFormatCtx->streams[i];             // 输入流
    AVCodecParameters* in_codeper = in_stream->codecpar;   // 编解码器
    // 只取音频流
    if (in_codeper->codec_type == AVMEDIA_TYPE_AUDIO)
    {
      // 建立输出流
      out_stream = avformat_new_stream(pFormatCtx_out, NULL);
      if (NULL == out_stream)
      {
        printf("Ffmpeg::extractAudio::[ERROR]建立输出流失败\n");
        return false;
      }
      // 拷贝编码参数,如果需要转码请不要直接拷贝
      // 这里只需要做音频的提取,对转码要求不高
      ret = avcodec_parameters_copy(out_stream->codecpar, in_codeper); // 将输入流的编码拷贝到输出流
      if (ret < 0)
      {
        printf("Ffmpeg::extractAudio::[ERROR]拷贝编码失败\n");
        return false;
      }
      out_stream->codecpar->codec_tag = 0;
      break;  // 拿到音频流就可以直接退出循环,这里我们只需要音频流
    }
  }
  av_dump_format(pFormatCtx_out, 0, szFilename, 1);
  // 解复用器,如果没有指定就使用pb
  if (!(pFormatCtx->flags & AVFMT_NOFILE))
  {
    ret = avio_open(&pFormatCtx_out->pb, szFilename, AVIO_FLAG_WRITE); // 读写
    if (ret < 0)
    {
      printf("Ffmpeg::extractAudio::[ERROR]创建AVIOContext对象:打开文件失败\n");
      return false;
    }
  }
  // 写入媒体文件头部
  ret = avformat_write_header(pFormatCtx_out, NULL);
  if (ret < 0)
  {
    printf("Ffmpeg::extractAudio::[ERROR]写入媒体头部失败\n");
    return false;
  }
  // 逐帧提取音频
  AVPacket* pkt = av_packet_alloc();
  while (av_read_frame(pFormatCtx, &packet) >=0 )
  {
    AVStream* in_stream  = NULL;
    AVStream* out_stream = NULL;
    in_stream = pFormatCtx->streams[pkt->stream_index];
    out_stream = pFormatCtx_out->streams[pkt->stream_index];
    if (packet.stream_index == audio_stream_index)
    {
      packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
      packet.dts = packet.pts;
      packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
      packet.pos = -1;
      packet.stream_index = 0;
      // 将包写到输出媒体文件
      av_interleaved_write_frame(pFormatCtx_out, &packet);
      // 减少引用计数,防止造成内存泄漏
      av_packet_unref(&packet);
    }
  }
  // 写入尾部信息
  av_write_trailer(pFormatCtx_out);
  // 释放
  av_packet_free(&pkt);
  avio_close(pFormatCtx_out->pb);
  avformat_close_input(&pFormatCtx);
    return true;
}

3.性能对比

5s

5min

30min

0.087017s

0.138014s

0.875926s

三、视频文件中提取图片

1.FFmpeg 

通过命令行

ffmpeg -i 视频文件名 -r 帧率 -f 输出格式 输出文件名

示例: ffmpeg -i video.mp4 -r 1 -f image2 image-%3d.png

参数说明:

-r 帧率(一秒内导出多少张图像,默认25)

-f 代表输出格式(image2实际上是image2序列的意思)

示例:

通过提供的API

bool AVInterface::extracPictrue(const char* src, const char* dstDir, int num)
{
    if(NULL == src || NULL == dstDir)
    {
        printf("Ffmpeg::extracPictrue[ERROR]::无效参数,请检查文件路径是否正确\n");
        return false;
    }
    int ret = 0;
    // 预存原文件路径
    const char* src_fileName = src;
    // 1.获取媒体文件的全局上下文信息
    // 1.1 定义 AVFormatContext 容器
    AVFormatContext* pFormatCtx = NULL;       // AVFormatContext描述了一个媒体文件或者媒体流构成的基本信息
    pFormatCtx = avformat_alloc_context();    // 为pFormatCtx申请内存
    // 1.2 打开媒体文件,并且读取媒体文件的头信息放入pFormatCtx中
    ret = avformat_open_input(&pFormatCtx, src_fileName, NULL, NULL);
    if(ret < 0)
    {
        printf("Ffmpeg::extracPictrue[ERROR]::打开媒体流文件失败\n");
        return false;
    }
    // 2.探测流信息
    // 2.1 探寻文件中是否存在信息流,如果存在则将多媒体文件信息流放到pFormatCtx中
    ret = avformat_find_stream_info(pFormatCtx, NULL);
    if(ret < 0)
    {
        printf("Ffmpeg::extracPictrue[ERROR]::文件中不存在信息流\n");
        return false;
    }
    av_dump_format(pFormatCtx, 0, src_fileName, 0);      // 可以打印查看
    // 2.2 查找文件信息流中是否存在视频流(这里我们需要提取图片),并获取到视频流在信息流中的索引
    int vecdio_stream_index = -1;
    vecdio_stream_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if(-1 == vecdio_stream_index)
    {
        printf("Ffmpeg::extracPictrue[ERROR]::文件中不存在视频流\n");
        return false;
    }   // ----------> 丛林方法1
    // 3.找到对应的解码器:音视频文件是压缩之后的,我们要对文件内容进行处理,就必须先解码
    // 3.1 定义解码器的容器
    AVCodecContext* pCodeCtx = NULL;          // AVCodecContext描述编解码器的结构,包含了众多解码器的基本信息
    const AVCodec* pCodec = NULL;                   // AVCodec 存储解码器的信息
  pCodeCtx = avcodec_alloc_context3(NULL);  // 初始化解码器上下文
    // 3.2 查找解码器
    AVStream* pStream = pFormatCtx->streams[vecdio_stream_index]; // 在众多解码器找到视频处理的上下文信息
    pCodec = avcodec_find_decoder(pStream->codecpar->codec_id);          // 根据视频流获取视频解码器的基本信息
    if(NULL == pCodec)
    {
        printf("未发现视频编码器\n");
        return false;
    }
  // 初始化解码器上下文
  ret = avcodec_parameters_to_context(pCodeCtx, pStream->codecpar);
  if (ret < 0)
  {
    printf("初始化解码器上下文失败\n");
    return false;
  }
    // 3.3 打开解码器
    ret = avcodec_open2(pCodeCtx, pCodec, NULL);
    if(ret < 0)
    {
        printf("无法打开编解码\n");
        return false;
    }
  AVFrame* pFrame = NULL;
  pFrame = av_frame_alloc();
  if (NULL == pFrame)
  {
    printf("av_frame_alloc is error\n");
    return false;
  }
  int index = 0;
  AVPacket avpkt;
  while (av_read_frame(pFormatCtx, &avpkt) >= 0)
  {
    if (avpkt.stream_index == vecdio_stream_index)
    {
      ret = avcodec_send_packet(pCodeCtx, &avpkt);
      if (ret < 0)
      {
        continue;
      }
      while (avcodec_receive_frame(pCodeCtx, pFrame) == 0)
      {
        SaveFramePicture(pFrame, dstDir, index);
      }
      index++;
      if (index == num)
      {
        break;
      }
    }
    av_packet_unref(&avpkt);
  }
    avcodec_close(pCodeCtx);
    avformat_close_input(&pFormatCtx);
    return true;
}
bool AVInterface::SaveFramePicture(AVFrame* pFrame, const char* dstDir, int index)
{
    char szFilename[256] = {0};
    snprintf(szFilename, sizeof(szFilename), "%s/ffmpeg-%d.png", dstDir, index);
    int ret = 0;
  int width  = pFrame->width;
  int height = pFrame->height;
    // 1.初始化图片封装格式的结构体
    AVCodecContext*  pCodeCtx = NULL;
    AVFormatContext* pFormatCtx = NULL;
    pFormatCtx = avformat_alloc_context(); 
    // 2.设置封装格式
  // MJPEG格式:按照25帧/秒速度使用JPEG算法压缩视频信号,完成动态视频的压缩 --> 视频文件使用MJPEG进行解压
    pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);  // 用于从已经注册的输出格式中寻找最匹配的输出格式
    // 3.创建AVIOContext对象:打开文件  
    ret = avio_open(&pFormatCtx->pb, szFilename, AVIO_FLAG_READ_WRITE); // 读写方式
    if(ret < 0)
    {
        printf("avio_open is error");
        return false;
    }
    // 构建一个新的stream
    AVStream* pAVStream = NULL;
    pAVStream = avformat_new_stream(pFormatCtx, 0);
    if(pAVStream == NULL)
    {
        printf("avformat_new_stream\n");
        return false;
    }
    AVCodecParameters* parameters = NULL;                    // 编码器参数的结构体
    parameters = pAVStream->codecpar;                        // 设置编码器 mjpeg
    parameters->codec_id = pFormatCtx->oformat->video_codec; // 视频流
    parameters->codec_type = AVMEDIA_TYPE_VIDEO;             // 编码类型
    //parameters->format = AV_PIX_FMT_BGR24;                 // 指定图片的显示样式
  parameters->format = AV_PIX_FMT_YUVJ420P;                // YUV 解压缩显示样式都是YUV
    parameters->width  = pFrame->width;                      // 指定图片的宽度
    parameters->height = pFrame->height;                     // 显示图片的高度
    // 找到相应的解码器
    const AVCodec* pCodec = avcodec_find_encoder(pAVStream->codecpar->codec_id);
    if(NULL == pCodec)
    {
        printf("avcodec_find_encoder is error\n");
        return false;
    }
    // 初始化解码器上下文
    pCodeCtx = avcodec_alloc_context3(pCodec);
    if(NULL == pCodeCtx)
    {
        printf("avcodec_alloc_context3 is error\n");
        return false;
    }
    // 设置解码器的参数
    //ret = avcodec_parameters_to_context(pCodeCtx, pAVStream->codecpar);
  ret = avcodec_parameters_to_context(pCodeCtx, parameters);
  if(ret < 0)
    {
        printf("avcodec_parameters_to_context is error\n");
        return false;
    }
  AVRational avrational = {1, 25};       
  pCodeCtx->time_base = avrational;
  // 打开编解码器
    ret = avcodec_open2(pCodeCtx, pCodec, NULL);
    if(ret < 0)
    {
        printf("avcodec_open2 is error\n");
        return false;
    }
    // 封装格式的头部信息写入
    ret = avformat_write_header(pFormatCtx, NULL);
    if(ret < 0)
    {
        printf("avformat_write_header is error\n");
        return false;
    }
    // 给AVPacket分配足够大的空间
    int y_size = width * height;    // 分辨率
    AVPacket pkt;
    av_new_packet(&pkt, y_size * 3);
    // 编码数据
    ret = avcodec_send_frame(pCodeCtx, pFrame);
    if(ret < 0)
    {
        printf("avcodec_send_frame is error\n");
        return false;
    }
    // 得到解码之后的数据
    ret = avcodec_receive_packet(pCodeCtx, &pkt);
    if(ret < 0)
    {
        printf("avcodec_receive_packet is error\n");
        return false;
    }
    ret = av_write_frame(pFormatCtx, &pkt);
    if(ret < 0)
    {
        printf("av_write_frame is error\n");
        return false;
    }
  av_packet_unref(&pkt);
  av_write_trailer(pFormatCtx);
  avcodec_close(pCodeCtx);
  avio_close(pFormatCtx->pb);
  avformat_free_context(pFormatCtx);
    return true;
}

3.性能对比

5s

5min

30min

10张

0.295322s

0.146283s

0.151467s

100张

1.263546s

1.226884s

1.190490s

全部

2.670444s(170)

96.951886s(7514)

119.161211s(10000)

四、音频文件中提取文字

1.百度智能云语音识别

百度语音目前只支持语音识别,语音合成和语音唤醒,支持pcm wav amr三种格式,时长为60秒以内,价格为完全免费,调用量限制为无限制

1、离线语音识别

百度离线语音识别目前只支持Android和IOS,Android 平台的一体化离在线语音识别解决方案,以JAR包 + SO库的形式发布。IOS移动设备的离在线语音识别解决方案,以静态库方式提供。

2、在线语音识别

通过API格式调用,Android,iOS,C#,Java,Node,PHP,Python,C++语言,其实是API模式,所有开发语言都支持

1.1百度智能云的优劣

  • 支持普通话,英语,粤语,四川话,普通话远场
  • 只支持60秒以内识别
  • 所有开发语言都支持
  • 百度的linux版离线SDK支持centos 和 ubantu14 16
  • 需要注册百度云控制台账号

1.2 百度智能云安装配置

安装必要的依赖,curl(必须带ssl) jsoncpp openssl

#安装libcurl

sudo apt-get install libcurl4-openssl-dev

#安装jsoncpp

sudo apt-get install libjsoncpp-dev

直接使用开发包步骤如下

  • 官方网站下载C++ SDK压缩包。SDK下载_文字识别SDK_语音识别SDK-百度AI开放平台 (baidu.com)
  • 将下载的aip-cpp-sdk-version.zip解压, 其中文件为包含实现代码的头文件。
  • 安装依赖库libcurl(需要支持https) openssl jsoncpp(>1.6.2版本,0.x版本将不被支持)
  • 编译工程时添加 C++11 支持 (gcc/clang 添加编译参数 -std=c++11), 添加第三方库链接参数 lcurl, lcrypto, ljsoncpp。
  • 在源码中include speech.h ,引入压缩包中的头文件以使用aip命名空间下的类和方法。

1.4百度智能云使用示例

用户可以参考如下代码新建一个client:

#include "speech.h"

    // 设置APPID/AK/SK

    std::string app_id = "XXX";

    std::string api_key = "XXX";

    std::string secret_key = "XXX";

    aip::Speech client(app_id, api_key, secret_key);

        在上面代码中,常量APP_ID在百度云控制台中创建,常量API_KEYSECRET_KEY是在创建完毕应用后,系统分配给用户的,均为字符串,用于标识用户,为访问做签名验证,可在AI服务控制台中的应用列表中查看。

向远程服务上传整段语音进行识别

void asr(aip::Speech client)

{

    // 无可选参数调用接口

    std::string file_content;

    aip::get_file_content("./assets/voice/16k_test.pcm", &file_content);

    Json::Value result = client.recognize(file_content, "pcm", 16000, aip::null);

    // 极速版调用函数

    // Json::Value result = client.recognize_pro(file_content, "pcm", 16000, aip::null);

    // 如果需要覆盖或者加入参数

    std::map<std::string, std::string> options;

    options["dev_pid"] = "1537";

    Json::Value result = client.recognize(file_content, "pcm", 16000, options);

}

返回样例:

// 成功返回

{

    "err_no": 0,

    "err_msg": "success.",

    "corpus_no": "15984125203285346378",

    "sn": "481D633F-73BA-726F-49EF-8659ACCC2F3D",

    "result": ["北京天气"]

}

// 失败返回

{

    "err_no": 2000,

    "err_msg": "data empty.",

    "sn": null

}

SpeechRecognition开源离线语音识别

      SpeechRecognition,是google出的,专注于语音向文本的转换。wit 和 apiai 提供了一些超出基本语音识别的内置功能,如识别讲话者意图的自然语言处理功能。

SpeechRecognition的优/劣

  • 满足几种主流语音 API ,灵活性高
  • Google Web Speech API 支持硬编码到 SpeechRecognition 库中的默认 API 密钥,无需注册就可使用
  • 易用性很高
  • python的语音识别库
  • 中国的识别效果不是特别好

SpeechRecognition安装配置

SpeechRecognition安装配置

pip install SpeechRecognition (pip install -i https://pypi.tuna.tsinghua.edu.cn/simple SpeechRecognition)

yum install python3-devel

yum install pulseaudio-libs-devel

yum install alse-lib-devel

pip install packetSphinx   

配置中文语音识别数据

下载地址

https://sourceforge.net/projects/cmusphinx/files/Acoustic%20and%20Language%20Models/

选择

Mandarin->cmusphinx-zh-cn-5.2.tar.gz

安装中文语音包

cd /usr/local/python3.6.8/lib/python3.6/site-packages/speech_recognition/pocketsphinx-data

tar zxvf cmusphinx-zh-cn-5.2.tar.gz

mv cmusphinx-zh-cn-5.2 zh-cn

cd zh-cn

mv zh_cn.cd_cont_5000 acoustic-model

mv zh_cn.lm.bin language-model.lm.bin

mv zh_cn.dic pronounciation-dictionary.dict

配置环境

cd /usr/local/python3.6.8/lib/python3.6/site-packages/speech_recognition/pocketsphinx-data

tar zxvf py36asr.tar.gz

source ./py36asr/bin/activate

SpeechRecognition使用示例

语音识别示例:

[root@localhost pocketsphinx-data]# pwd

/usr/local/python3.6.8/lib/python3.6/site-packages/speech_recognition/pocketsphinx-data

[root@localhost pocketsphinx-data]# ls

cmusphinx-zh-cn-5.2.tar.gz  py36asr         test1.py   test2.wav  zh-cn.tar.gz

en-US                       py36asr.tar.gz  test1.wav  zh-cn

程序示例:

# -*- coding: utf-8 -*-

# /usr/bin/python

import speech_recognition as sr

r = sr.Recognizer()    

test = sr.AudioFile("test1.wav")

with test as source:       

    audio = r.record(source)

type(audio)

c=r.recognize_sphinx(audio, language='zh-cn')    

print(c)

FastASR语音识别

       这是一个用C++实现ASR推理的项目,它的依赖很少,安装也很简单,推理速度很快。支持的模型是由Google的Transformer模型中优化而来,数据集是开源。Wennetspeech(1000+小时)或阿里私有数据集(60000+小时),所以识别效果有很好,可以媲美许多商用的ASR软件。

  • 流式模型:模拟的输入是语音流,并实时返回语音识别的结果,但是准确率会降低些。

名称

来源

数据集

模型

conformer_online

paddlespeech

WenetSpeech(1000h)

conformer_online_wenetspeech-zh-16k

  • 非流式模型:每次识别是以句子为单位,所以实时性会差一些,但是准确率会高一些。

名称

来源

数据集

模型

语言

paraformer

阿里达摩院

私有数据集(6000h)

Paraformer-large

En+zh

k2_rnnt2

kaldi2

WenetSpeech(10000h)

Prouned_transducer_stateless2

zh

Conformer_online

paddlespeech

WenetSpeech(10000h)

Conformer_online_wenetspeech-zh-16k

zh

       上面提到的这些模型都是基于深度学习框架(paddlepaddle和pytorch)实现的,本身的性能很不错,在个人电脑上运行,也能满足实时性要求(时长为10s的语言,推理视觉小于10s,即可满足实时性)。

FastASR的优/劣

  • 语言优势:由于C++和Python不同,是编译型语言,编译器会根据编译选项针对不同的平台的CPU进行优化,更合适在不同CPU平台上面部署,充分利用CPU的计算资源。
  • 实现独立:不依赖于现有的深度学习框架如pytorch、paddle、tensorflow等
  • 依赖少:项目仅使用了两个第三方libfftw和libopenblas,并无其它依赖,所以在各个平台的可以移植性很好,通用性很强。

  •  缺少量化和压缩模型
  •  支持C++ 和python

FastASR安装配置

  1. 依赖安装库 libfftw3

sudo apt-get install libfftw3-dev libfftw3-single3

  1. 安装依赖库 libopenblas

sudo apt-get install libopenblas-dev

  1. 安装python环境

sudo apt-get install python3 python3-dev

  1. 下载最新版的源码
  1. 编译最新版本的源码

cd FastASR/

mkdir build

cd build

cmake -DCMAKE_BUILD_TYPE=Release ..

make

  1. 编译python的whl安装包

cd FastASR

python -m build

  1. 下载预训练模型

paraformer预训练模型下载

cd ../models/paraformer_cli

1.从modelscope官网下载预训练模型

wget --user-agent="Mozilla/5.0" -c "https://www.modelscope.cn/api/v1/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/repo?Revision=v1.0.4&FilePath=model.pb"

  1. 重命名

mv repo\?Revision\=v1.0.4\&FilePath\=model.pb model.pb

  1. 将用于Python的模型转换为C++的

../scripts/paraformer_convert.py model.pb

  1. 通过md5检查是否等于 c77bce5758ebdc28a9024460e48602 

md5sum -b wenet_params.bin

K2_rnnt2预训练模型下载

cd ../models/k2_rnnt2_cli

1.从huggingface官网下载预训练模型

wget -c https://huggingface.co/luomingshuang/icefall_asr_wenetspeech_pruned_transducer_stateless2/resolve/main/exp/pretrained_epoch_10_avg_2.pt

2.将用于Python的模型转换为C++的

../scripts/k2_rnnt2_convert.py pretrained_epoch_10_avg_2.pt

3.通过md5检查是否等于 33a941f3c1a20a5adfb6f18006c11513

 md5sum -b wenet_params.bin

PaddleSpeech预训练模型下载

1.从PaddleSpeech官网下载预训练模型

wget -c https://paddlespeech.bj.bcebos.com/s2t/wenetspeech/asr1_conformer_wenetspeech_ckpt_0.1.1.model.tar.gz

2.将压缩包解压wenetspeech目录下

mkdir wenetspeech

tar -xzvf asr1_conformer_wenetspeech_ckpt_0.1.1.model.tar.gz -C wenetspeech

3.将用于Python的模型转换为C++的

../scripts/paddlespeech_convert.py wenetspeech/exp/conformer/checkpoints/wenetspeech.pdparams

4.md5检查是否等于 9cfcf11ee70cb9423528b1f66a87eafd

md5sum -b wenet_params.bin

流模式预训练模型下载

cd ../models/paddlespeech_stream

  1. 从PaddleSpeech官网下载预训练模型

wget -c https://paddlespeech.bj.bcebos.com/s2t/wenetspeech/asr1/asr1_chunk_conformer_wenetspeech_ckpt_1.0.0a.model.tar.gz

2.将压缩包解压wenetspeech目录下

mkdir wenetspeech

tar -xzvf asr1_chunk_conformer_wenetspeech_ckpt_1.0.0a.model.tar.gz -C wenetspeech

3.将用于Python的模型转化为C++的

../scripts/paddlespeech_convert.py wenetspeech/exp/chunk_conformer/checkpoints/avg_10.pdparams

4.md5检查是否等于 367a285d43442ecfd9c9e5f5e1145b84

md5sum -b wenet_params.bin

FastASR使用示例

#include <iostream>
#include <win_func.h>
#include <Audio.h>
#include <Model.h>
#include <string.h>
using namespace std;
bool externContext(const char* src, const char* dst)
{
    Audio audio(0);           // 申请一个音频处理的对象
    audio.loadwav(src);       // 加载文件
    audio.disp();             // 分析格式
    // Model* mm = create_model("/home/chen/FastASR/models/k2_rnnt2_cli", 2); // 创建一个预训练模型
    Model* mm = create_model("/home/chen/FastASR/models/paraformer_cli", 3);
    audio.split();           // 解析文件
    float* buff = NULL;      // fftw3数据分析
    int len = 0;
    int flag = false;
    char buf[1024];
    // 一行一行的取出内容
    FILE* fp = NULL;
    fp = fopen(dst, "w+");
    if(NULL == fp)
    {
        printf("打开文件失败\n");
    }
    printf("0.---------------------->\n");
    while(audio.fetch(buff, len , flag) > 0)
    {
        printf("1.---------------------->\n");
        mm->reset();
        string msg = mm->forward(buff, len, flag);
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf), "%s", msg.c_str());
        fseek(fp, 0, SEEK_END);
        fprintf(fp, "%s\n", buf);
        fflush(fp);
        printf("2.--------------------->\n");
    }
    printf("3.------------------------>\n");
    return true;
}
int main(void)
{
    externContext("./long.wav", "./Context.txt");
    return 0;
}
flags:= -I ./include
flags+= -L ./lib -lfastasr -lfftw3 -lfftw3f -lblas  -lwebrtcvad
src_cpp=$(wildcard ./*.cpp)
debug:
  g++ -g $(src_cpp) -omain $(flags) -std=c++11

夜深了,这篇文章中的从之前写的文档里粘贴过来的。有一些地方格式不太好看。见谅...

相关实践学习
达摩院智能语音交互 - 声纹识别技术
声纹识别是基于每个发音人的发音器官构造不同,识别当前发音人的身份。按照任务具体分为两种: 声纹辨认:从说话人集合中判别出测试语音所属的说话人,为多选一的问题 声纹确认:判断测试语音是否由目标说话人所说,是二选一的问题(是或者不是) 按照应用具体分为两种: 文本相关:要求使用者重复指定的话语,通常包含与训练信息相同的文本(精度较高,适合当前应用模式) 文本无关:对使用者发音内容和语言没有要求,受信道环境影响比较大,精度不高 本课程主要介绍声纹识别的原型技术、系统架构及应用案例等。 讲师介绍: 郑斯奇,达摩院算法专家,毕业于美国哈佛大学,研究方向包括声纹识别、性别、年龄、语种识别等。致力于推动端侧声纹与个性化技术的研究和大规模应用。
相关文章
|
30天前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
105 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
1月前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
57 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
1月前
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
139 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
|
1月前
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
74 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
|
2月前
|
XML Java Android开发
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
GSYVideoPlayer是一款国产移动端视频播放器,支持弹幕、滤镜、广告等功能,采用IJKPlayer、Media3(EXOPlayer)、MediaPlayer及AliPlayer多种内核。截至2024年8月,其GitHub星标数达2万。集成时需使用新版Android Studio,并按特定步骤配置依赖与权限。提供了NormalGSYVideoPlayer、GSYADVideoPlayer及ListGSYVideoPlayer三种控件,支持HLS、RTMP等多种直播链接。
100 18
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
|
1月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
85 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
EasyPusher是一款国产RTSP直播录制推流客户端工具,支持Windows、Linux、Android及iOS等系统。尽管其GitHub仓库(安卓版:https://github.com/EasyDarwin/EasyPusher-Android)已多年未更新,但通过一系列改造,如升级SDK版本、迁移到AndroidX、指定本地NDK版本及更新Gradle版本等,仍可在最新Android Studio上运行。以下是针对Android Studio Dolphin版本的具体改造步骤。
60 3
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
|
1月前
|
Android开发 开发者
FFmpeg开发笔记(五十七)使用Media3的Transformer加工视频文件
谷歌推出的Transformer,作为Jetpack Media3架构的一部分,助力开发者实现音视频格式转换与编辑。Media3简化了媒体处理流程,提升了定制性和可靠性。Transformer可用于剪辑、添加滤镜等操作,其示例代码可在指定GitHub仓库中找到。要使用Transformer,需在`build.gradle`中添加相关依赖,并按文档编写处理逻辑,最终完成音视频转换任务。具体步骤包括配置剪辑参数、设置空间效果以及监听转换事件等。
52 0
FFmpeg开发笔记(五十七)使用Media3的Transformer加工视频文件
|
1月前
|
Linux 视频直播
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
本文介绍了如何使用EasyPusher-Android实现RTSP直播流程。首先对比了RTSP、RTMP、SRT和RIST四种流媒体协议,并以RTSP为例,详细说明了使用EasyPusher-Android向流媒体服务器进行RTSP直播推流的方法。文中还提供了OBS Studio配置RTSP插件及ZLMediaKit云服务器部署的相关信息,通过修改EasyPusher-Android源码使其支持通用RTSP地址,最终验证了直播功能的成功实现。
56 0
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
|
2月前
|
编解码 移动开发 安全
FFmpeg开发笔记(五十)聊聊几种流媒体传输技术的前世今生
自互联网普及以来,流媒体技术特别是视频直播技术不断进步,出现了多种传输协议。早期的MMS由微软主导,但随WMV格式衰落而减少使用。RTSP由网景和RealNetworks联合提出,支持多种格式,但在某些现代应用中不再受支持。RTMP由Adobe开发,曾广泛用于网络直播,但因HTML5不支持Flash而受影响。HLS由苹果开发,基于HTTP,适用于点播。SRT和RIST均为较新协议,强调安全与可靠性,尤其SRT在电视直播中应用增多。尽管RTMP仍占一定市场,但SRT等新协议正逐渐兴起。
102 8
FFmpeg开发笔记(五十)聊聊几种流媒体传输技术的前世今生

热门文章

最新文章

下一篇
无影云桌面