Encoding FFmpeg API-转码和发送脉冲音频输入(rtsp)

Encoding FFmpeg API-转码和发送脉冲音频输入(rtsp),encoding,ffmpeg,transcoding,Encoding,Ffmpeg,Transcoding,我的目标是读取pulseaudio麦克风音频输入,并通过编码为opus的rtsp发送。要播放流,我使用ffplay 我错过了哪一步?目前我在接收流时只听到噪音。有趣的是,av_dump_格式显示正确的输出: Input #0, pulse, from 'default': Duration: N/A, start: 1602879120.276839, bitrate: 1536 kb/s Stream #0:0: Audio: pcm_s16le, 48000 Hz, 2 chan

我的目标是读取pulseaudio麦克风音频输入,并通过编码为opus的rtsp发送。要播放流,我使用ffplay

我错过了哪一步?目前我在接收流时只听到噪音。有趣的是,
av_dump_格式
显示正确的输出:

Input #0, pulse, from 'default':
  Duration: N/A, start: 1602879120.276839, bitrate: 1536 kb/s
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 2 channels, s16, 1536 kb/s
Output #0, rtsp, to 'rtsp://localhost:8191/call':
    Stream #0:0: Audio: opus, 8000 Hz, mono, s16, 16 kb/s

但ffplay显示不同的流参数:

Input #0, rtsp, from 'rtsp://localhost:8191/call':sq=    0B f=0/0   
  Metadata:
    title           : No Name
  Duration: N/A, start: 51444.871521, bitrate: N/A
    Stream #0:0: Audio: opus, 48000 Hz, stereo, fltp

#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
int-ret,got_帧,got_包;
常量字符*音频输入;
常量字符*输出;
AVOutputFormat*out\U format=NULL;
AVInputFormat*in_format=NULL;
AVFormatContext*格式为\u ctx=NULL;
AVFormatContext*out\u format\u ctx=NULL;
AVCodec*in_codec=NULL;
AVCODECTCONTEXT*in_codec_ctx=NULL;
AVCodec*out_codec=NULL;
AVCodecContext*out\u codec\u ctx=NULL;
AVPacket packet={.data=NULL,.size=0};
AVFrame*frame=NULL;
AVDictionary*opt=NULL;
AVStream*ost;
av_寄存器_all();
avdevice_register_all();
音频输入=argv[1];
输出=argv[2];
//输入
//以选定格式打开输入
in_format=av_find_input_format(“脉冲”);
if((ret=avformat\u open\u输入(&in\u format\u ctx,audio\u输入,in\u format,NULL))!=0)
{
fprintf(stderr,“无法打开音频输入:%s.%s\n”,音频输入,av_err2str(ret));
出口(1);
}
//在标题中查找流信息并显示
if((ret=avformat\u find\u stream\u info(in\u format\u ctx,NULL))流[0]->codec->codec\u id);
if(in_codec==NULL){
fprintf(stderr,“不支持的解码器。\n”);
出口(1);
}
//为麦克风输入编解码器上下文分配内存(所有信息)
in_codec_ctx=avcodec_alloc_context3(in_codec);
if((ret=avcodec\u copy\u上下文(在\u codec\u ctx中,在\u格式\u ctx->streams[0]->codec))!=0){
fprintf(stderr,“无法复制编解码器上下文。%s\n”,av_err2str(ret));
出口(1);
}
//使用选定的编解码器和编解码器上下文
格式的if((ret=avcodec_open2(in_codec_ctx,in_codec,NULL));
/*如果需要,请打开输出文件*/
out\u codec=avcodec\u find\u编码器(AV\u codec\u ID\u OPUS);
if(out_codec==NULL){
fprintf(stderr,“不支持的编码器。\n”);
出口(1);
}
out\u codec\u ctx=avcodec\u alloc\u context3(out\u codec);
如果(!out\u codec\u ctx){
fprintf(stderr,“无法分配编码上下文\n”);
出口(1);
}
/*检查编码器是否支持s16 pcm输入*/
out_codec_ctx->sample_fmt=AV_sample_fmt_S16;
out_codec_ctx->比特率=16000;
out_codec_ctx->采样率=8000;
out_codec_ctx->channels=1;
out_codec_ctx->channel_layout=AV_Chu layout_MONO;
out\u codec\u ctx->channels=av\u get\u channel\u layout\u nb\u channels(out\u codec\u ctx->channel\u layout);
if(输出格式ctx->oformat->标志和AVFMT\U全局标题)
out_codec_ctx->flags |=AV_codec_FLAG_GLOBAL_头;
ret=avcodec_open2(out_codec_ctx,out_codec,NULL);
如果(ret<0){
fprintf(stderr,“无法打开音频编解码器:%s\n”,av_err2str(ret));
出口(1);
}
ost=avformat\ U new\ U stream(out\ U format\ U ctx,NULL);
如果(!ost){
fprintf(stderr,“无法分配流”\n);
出口(1);
}
ost->id=0;
ret=来自上下文的avcodec参数(ost->codecpar,out codec\U ctx);
如果(ret<0){
av_日志(NULL,av_日志错误,“无法将编码器参数复制到输出流。%s\n”,av_err2str(ret));
返回ret;
}
ost->time\u base=out\u codec\u ctx->time\u base;
av_转储_格式(out_格式_ctx,0,输出,1);
/*将流参数复制到muxer*/
ret=来自上下文的avcodec参数(ost->codecpar,out codec\U ctx);
如果(ret<0){
fprintf(stderr,“无法复制流参数。%s\n”,av_err2str(ret));
出口(1);
}
如果(!(输出格式ctx->oformat->flags&AVFMT\U NOFILE)){
ret=avio_打开(&out_格式\u ctx->pb,输出,avio_标志\u写入);
如果(ret<0){
av_日志(NULL,av_日志错误,“无法打开输出文件“%s”,输出);
返回ret;
}
}
/*初始化muxer,写入输出文件头*/
ret=avformat\U write\U头(out\U format\U ctx,NULL);
如果(ret<0){
av_日志(NULL,av_日志_错误,“打开输出文件时出错\n”);
返回ret;
}
而(1)
{
如果((ret=av_读取_帧(格式为ctx和数据包))<0)
{
fprintf(stderr,“读取帧失败。%s\n”,av_err2str(ret));
打破
}
frame=av_frame_alloc();
如果(!帧){
ret=平均值(ENOMEM);
打破
}
av_数据包\u重新缩放\u ts(数据包,格式为\u ctx->streams[0]->时基,编码解码器\u ctx->时基);
如果((ret=avcodec\U decode\U audio4(in\U codec\U ctx、帧和got\U帧和数据包))<0)
{
av_无帧(&帧);
fprintf(stderr,“音频解码失败。%s\n”,av_err2str(ret));
打破
}
frame->nb\u samples=out\u codec\u ctx->frame\u size;
如果((ret=av_帧_获取_缓冲区(帧,0))
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  int ret,got_frame,got_packet;
  const char *audio_input;
  const char *output;
  AVOutputFormat *out_format = NULL;
  AVInputFormat *in_format = NULL;
  AVFormatContext *in_format_ctx = NULL;
  AVFormatContext *out_format_ctx = NULL;
  AVCodec *in_codec = NULL;
  AVCodecContext *in_codec_ctx = NULL;
  AVCodec *out_codec = NULL;
  AVCodecContext *out_codec_ctx = NULL;
  AVPacket packet = { .data = NULL, .size = 0 };
  AVFrame *frame = NULL;
  AVDictionary *opt = NULL;
  AVStream *ost;

  av_register_all();
  avdevice_register_all();

  audio_input = argv[1];
  output = argv[2];

  //INPUT
  //Open input in selected format
  in_format = av_find_input_format("pulse");
  if((ret = avformat_open_input(&in_format_ctx, audio_input, in_format, NULL))!=0)
  {
    fprintf(stderr,"Could not open audio input: %s. %s\n",audio_input,av_err2str(ret));
    exit(1);
  }

  //Find stream info in header and display
  if((ret = avformat_find_stream_info(in_format_ctx, NULL))<0)
  {
    fprintf(stderr,"Could not find stream information. %s\n",av_err2str(ret));
    exit(1);
  }

  av_dump_format(in_format_ctx, 0, audio_input, 0);

  in_codec = avcodec_find_decoder(in_format_ctx->streams[0]->codec->codec_id);
  if(in_codec==NULL) {
    fprintf(stderr, "Unsupported decoder.\n");
    exit(1);
  }

  //Allocate memory for microphone input codec context (all information)
  in_codec_ctx = avcodec_alloc_context3(in_codec);
  if((ret = avcodec_copy_context(in_codec_ctx, in_format_ctx->streams[0]->codec)) != 0) {
    fprintf(stderr, "Couldn't copy codec context. %s\n",av_err2str(ret));
    exit(1);
  }

  //Use selected codec and codec context
  if((ret = avcodec_open2(in_codec_ctx, in_codec, NULL))<0)
  {
    fprintf(stderr, "Could not open audio codec. %s\n",av_err2str(ret));
    exit(1);
  }


  //OUTPUT
  ret = avformat_alloc_output_context2(&out_format_ctx, NULL, "rtsp", output);
  if (!out_format_ctx) {
    fprintf(stderr, "Output format ptoblem. %s\n",av_err2str(ret));
    exit(1);
  }

  out_format = out_format_ctx->oformat;
  /* open the output file, if needed */

  out_codec = avcodec_find_encoder(AV_CODEC_ID_OPUS);
  if(out_codec==NULL) {
    fprintf(stderr, "Unsupported encoder.\n");
    exit(1);
  }

  out_codec_ctx = avcodec_alloc_context3(out_codec);
  if (!out_codec_ctx) {
    fprintf(stderr, "Could not alloc an encoding context\n");
    exit(1);
  }

  /* check that the encoder supports s16 pcm input */
  out_codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
  out_codec_ctx->bit_rate    = 16000;
  out_codec_ctx->sample_rate = 8000;
  out_codec_ctx->channels    = 1;
  out_codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;
  out_codec_ctx->channels        = av_get_channel_layout_nb_channels(out_codec_ctx->channel_layout);

  if (out_format_ctx->oformat->flags & AVFMT_GLOBALHEADER)
      out_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

  ret = avcodec_open2(out_codec_ctx, out_codec, NULL);
  if (ret < 0) {
    fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
    exit(1);
  }

  ost = avformat_new_stream(out_format_ctx, NULL);
  if (!ost) {
    fprintf(stderr, "Could not allocate stream\n");
    exit(1);
  }
  ost->id=0;

  ret = avcodec_parameters_from_context(ost->codecpar, out_codec_ctx);
  if (ret < 0) {
      av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream. %s\n",av_err2str(ret));
      return ret;
  }

  ost->time_base = out_codec_ctx->time_base;

  av_dump_format(out_format_ctx, 0, output, 1);

  /* copy the stream parameters to the muxer */
  ret = avcodec_parameters_from_context(ost->codecpar, out_codec_ctx);
  if (ret < 0) {
    fprintf(stderr, "Could not copy the stream parameters. %s\n",av_err2str(ret));
    exit(1);
  }

  if (!(out_format_ctx->oformat->flags & AVFMT_NOFILE)) {
      ret = avio_open(&out_format_ctx->pb, output, AVIO_FLAG_WRITE);
      if (ret < 0) {
          av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", output);
          return ret;
      }
  }

  /* init muxer, write output file header */
  ret = avformat_write_header(out_format_ctx, NULL);
  if (ret < 0) {
      av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
      return ret;
  }

  while(1)
  {
    if((ret = av_read_frame(in_format_ctx, &packet)) < 0)
    {
      fprintf(stderr, "Reading frame failed. %s\n",av_err2str(ret));
      break;
    }

    frame = av_frame_alloc();
    if (!frame) {
        ret = AVERROR(ENOMEM);
        break;
    }

    av_packet_rescale_ts(&packet,in_format_ctx->streams[0]->time_base,in_codec_ctx->time_base);

    if((ret = avcodec_decode_audio4(in_codec_ctx,frame,&got_frame,&packet)) < 0)
    {
      av_frame_free(&frame);
      fprintf(stderr, "Audio decoding failed. %s\n",av_err2str(ret));
      break;
    }

    frame->nb_samples = out_codec_ctx->frame_size;
    if((ret = av_frame_get_buffer(frame, 0))<0)
    {
      fprintf(stderr, "Error allocating an audio buffer. %s\n",av_err2str(ret));
      break;
    }

    if(got_frame)
    {
      if((ret = avcodec_encode_audio2(out_codec_ctx,&packet,frame,&got_packet)) < 0)
      {
        av_frame_free(&frame);
        fprintf(stderr, "Audio encoding failed. %d %s\n",ret,av_err2str(ret));
        break;
      }
    }
    av_frame_free(&frame);

    if(got_packet)
    {
      if((ret = av_interleaved_write_frame(out_format_ctx,&packet)) < 0)
      {
        av_packet_unref(&packet);
        fprintf(stderr, "Writing frame error. %s\n",av_err2str(ret));
        break;
      }
    }
    av_packet_unref(&packet);
  }
}