【问题标题】:libav live transcode to SFML SoundStream, garbled and noiselibav实时转码SFML SoundStream,乱码和噪音
【发布时间】:2021-09-03 17:02:02
【问题描述】:

我非常接近让这个工作,但使用输出样本格式或编解码器上下文似乎无法解决,也不知道从哪里开始。

#include <iostream>
#include <SFML/Audio.hpp>
#include "MyAudioStream.h"

extern "C"
{
#include <libavutil/opt.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/audio_fifo.h>
#include <libswresample/swresample.h>
}

void setupInput(AVFormatContext *input_format_context, AVCodecContext **input_codec_context, const char *streamURL)
{
  // av_find_input_format("mp3");
  avformat_open_input(&input_format_context, streamURL, NULL, NULL);
  avformat_find_stream_info(input_format_context, NULL);

  AVDictionary *metadata = input_format_context->metadata;
  AVDictionaryEntry *name = av_dict_get(metadata, "icy-name", NULL, 0);
  if (name != NULL)
  {
    std::cout << name->value << std::endl;
  }
  AVDictionaryEntry *title = av_dict_get(metadata, "StreamTitle", NULL, 0);
  if (title != NULL)
  {
    std::cout << title->value << std::endl;
  }

  AVStream *stream = input_format_context->streams[0];
  AVCodecParameters *codec_params = stream->codecpar;
  AVCodec *codec = avcodec_find_decoder(codec_params->codec_id);
  *input_codec_context = avcodec_alloc_context3(codec);

  avcodec_parameters_to_context(*input_codec_context, codec_params);
  avcodec_open2(*input_codec_context, codec, NULL);
}

void setupOutput(AVCodecContext *input_codec_context, AVCodecContext **output_codec_context)
{
  AVCodec *output_codec = avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE); // AV_CODEC_ID_PCM_S16LE ?? AV_CODEC_ID_PCM_S16BE
  *output_codec_context = avcodec_alloc_context3(output_codec);
  (*output_codec_context)->channels = 2;
  (*output_codec_context)->channel_layout = av_get_default_channel_layout(2);
  (*output_codec_context)->sample_rate = input_codec_context->sample_rate;
  (*output_codec_context)->sample_fmt = output_codec->sample_fmts[0]; // AV_SAMPLE_FMT_S16 ??
  avcodec_open2(*output_codec_context, output_codec, NULL);
}

void setupResampler(AVCodecContext *input_codec_context, AVCodecContext *output_codec_context, SwrContext **resample_context)
{
  *resample_context = swr_alloc_set_opts(
      *resample_context,
      output_codec_context->channel_layout,
      output_codec_context->sample_fmt,
      output_codec_context->sample_rate,
      input_codec_context->channel_layout,
      input_codec_context->sample_fmt,
      input_codec_context->sample_rate,
      0, NULL);
  swr_init(*resample_context);
}

MyAudioStream::MyAudioStream()
{
  input_format_context = avformat_alloc_context();
  resample_context = swr_alloc();
}

MyAudioStream::~MyAudioStream()
{
  // clean up
  avformat_close_input(&input_format_context);
  avformat_free_context(input_format_context);
}

void MyAudioStream::load(const char *streamURL)
{

  setupInput(input_format_context, &input_codec_context, streamURL);
  setupOutput(input_codec_context, &output_codec_context);
  setupResampler(input_codec_context, output_codec_context, &resample_context);

  initialize(output_codec_context->channels, output_codec_context->sample_rate);
}

bool MyAudioStream::onGetData(Chunk &data)
{

  // init
  AVFrame *input_frame = av_frame_alloc();
  AVPacket *input_packet = av_packet_alloc();
  input_packet->data = NULL;
  input_packet->size = 0;

  // read
  av_read_frame(input_format_context, input_packet);
  avcodec_send_packet(input_codec_context, input_packet);
  avcodec_receive_frame(input_codec_context, input_frame);

  // convert
  uint8_t *converted_input_samples = (uint8_t *)calloc(output_codec_context->channels, sizeof(*converted_input_samples));
  av_samples_alloc(&converted_input_samples, NULL, output_codec_context->channels, input_frame->nb_samples, output_codec_context->sample_fmt, 0);
  swr_convert(resample_context, &converted_input_samples, input_frame->nb_samples, (const uint8_t **)input_frame->extended_data, input_frame->nb_samples);

  data.sampleCount = input_frame->nb_samples;
  data.samples = (sf::Int16 *)converted_input_samples;

  // av_freep(&converted_input_samples[0]);
  // free(converted_input_samples);
  av_packet_free(&input_packet);
  av_frame_free(&input_frame);

  return true;
}

void MyAudioStream::onSeek(sf::Time timeOffset)
{
  // no op
}

sf::Int64 MyAudioStream::onLoop()
{
  // no loop
  return -1;
}

调用

#include <iostream>

#include "./MyAudioStream.h"

extern "C"
{
#include <libavutil/opt.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}

const char *streamURL = "http://s5radio.ponyvillelive.com:8026/stream.mp3";

int main(int, char **)
{

  MyAudioStream myStream;

  myStream.load(streamURL);

  std::cout << "Hello, world!" << std::endl;

  myStream.play();

  while (myStream.getStatus() == MyAudioStream::Playing)
  {
    sf::sleep(sf::seconds(0.1f));
  }

  return 0;
}

【问题讨论】:

    标签: c++ ffmpeg sfml libav


    【解决方案1】:

    我解决了。 swr_get_out_samples 返回的计数似乎是每个通道。我在设置sf::SoundStream::Chunk::sampleCount时乘以2,如:

    data.sampleCount = out_samples * 2;

    这行得通。

    【讨论】:

      猜你喜欢
      • 2013-12-24
      • 2014-04-23
      • 2023-03-10
      • 1970-01-01
      • 2015-05-21
      • 1970-01-01
      • 2015-10-18
      • 2019-04-11
      • 1970-01-01
      相关资源
      最近更新 更多