FFMPEG+SDL播放音频流

       SDL播放音频和视频一样,需要先解码,再播放;但音频的播放不同于视频,他需要调用扬声器,播放音频不像视频一样给一帧数据播放一帧,音频是扬声器将缓冲区的数据播放完之后再向程序拿取数据。
SDL播放音频流程:
1)初始化SDL:SDL_Init()
2)设置音频空间参数,并定义填充缓存区的回调函数:设置SDL_AudioSpec参数
3)打开音频设备:SDL_OpenAudio()
4)播放:SDL_PauseAudio(0)  //0表示播放,1表示暂停
5)关闭音频设备:SDL_CloseAudio()
6)退出SDL:SDL_Quit()

SDL播放音频流demo

#define SDL_MAIN_HANDLED //使用SDL必须定义的宏
#include 
#include 
using namespace std;

extern "C"
{
#include 
#include 
#include 
#include  //音频重采样保证解码后数据和播放设置的参数一样
#include 
}

const char* infile = "1.mp4";

static Uint8* pAudio_chunk; //音频数据缓存区
static Uint32 audio_len; //剩余长度
static Uint8* pAudio_pos; //当前位置
//填充音频设备缓冲区的回调函数
void fill_audio_buffer(void* userdata, Uint8* stream, int len)
{
  SDL_memset(stream, 0, len);
  // 判断是否有读到数据
  if (audio_len == 0)
    return;

  len = (len > audio_len ? audio_len : len);
  SDL_MixAudio(stream, pAudio_pos, len, SDL_MIX_MAXVOLUME); //对音乐数据进行混音
  pAudio_pos += len;
  audio_len -= len;
}

int main(int argv, char** argc)
{
 // const char* infile = argc[1];
  AVFormatContext* afc = avformat_alloc_context(); //初始化上下文结构体AVFormatContext
  if (avformat_open_input(&afc, infile, NULL, NULL) != 0)
  {
    cout << "open video error " << endl;
    return -1;
  }
  if (avformat_find_stream_info(afc, NULL) < 0) //获取流信息,更新上下文结构AVFormatContext
  {
    cout << "find stream error" << endl;
    return -1;
  }
  int audioflag = -1;
  AVCodec* vdecodec, * adecodec;
  AVCodecContext* acc = NULL;
  for (int i = 0; i < afc->nb_streams; ++i)
  {
    if (afc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)  //音频
    {
      audioflag = i;
      adecodec = avcodec_find_decoder(afc->streams[audioflag]->codecpar->codec_id);
      acc = avcodec_alloc_context3(adecodec);
      avcodec_parameters_to_context(acc, afc->streams[i]->codecpar);
      if (avcodec_open2(acc, adecodec, NULL) < 0)
      {
        cout << "open audio decodec error" << endl;
        return -1;
      }
    }
  }
  if (audioflag == -1)
  {
    cout << "audio stream not find" << endl;
    return -1;
  }

  int out_framesize = 1024;//nb_samples: AAC-1024 MP3-1152 
  uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO; //音频输出格式布局
  int out_nb_samples = out_framesize;
  AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_FLTP;
  int out_sample_rate = acc->sample_rate;//采样率
  int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
  //cout << "out_channels = " << out_channels << endl;

  int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
  uint8_t** audio_data_buffer = NULL;//存储转换后的数据,再编码AAC   
  
  //SDL
  SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER);
  //播放参数设置
  SDL_AudioSpec audioSpec; 
  audioSpec.freq = out_sample_rate; //DSP频率 相当于采样率
  audioSpec.format = AUDIO_S16SYS; //格式
  audioSpec.channels = out_channels; //通道数
  audioSpec.silence = 0; //静音值,一般为0
  audioSpec.samples = out_framesize; 
  audioSpec.callback = fill_audio_buffer; //回调
  audioSpec.userdata = acc; //用户数据
  int a = SDL_OpenAudio(&audioSpec, nullptr); //打开音频设备,第二个参数为播放音频的设备,NULL表示默认设备
  if (a < 0)
  {
    printf("Can not open audio! %d", a);
    return -1;
  }
  SDL_PauseAudio(0);

  //in_channel_layout = av_get_default_channel_layout(acc->channels);
  SwrContext *au_convert_ctx = swr_alloc();
  au_convert_ctx = swr_alloc_set_opts(au_convert_ctx,
    out_channel_layout,//输出
    out_sample_fmt, //编码前你希望的格式
    out_sample_rate,//输出
    av_get_default_channel_layout(acc->channels), //in_channel_layout, //输入
    acc->sample_fmt,//PCM源文件的采样格式
    acc->sample_rate, //输入
    0, NULL);
  swr_init(au_convert_ctx);

  int data_count = 0;
  AVFrame* aframe = av_frame_alloc();
  AVPacket pkt;//= (AVPacket*)av_malloc(sizeof(AVPacket));
  av_init_packet(&pkt);
  while (av_read_frame(afc, &pkt) >= 0)
  {
    if (pkt.stream_index == audioflag) //音频解码
    {
      int ret = 0;
      if (ret = avcodec_send_packet(acc, &pkt) != 0)
      {
        cout << "send audio packet to decodec error" << endl;
        return -1;
      }
      while (ret >= 0)
      {
        ret = avcodec_receive_frame(acc, aframe);
        if (ret == 0)
        {
          int audio_buffersize = aframe->linesize[0];//av_samples_get_buffer_size(NULL, acc->channels, acc->frame_size, acc->sample_fmt, 1); //获取音频数据大小
          cout << "channels = " << acc->channels << "rate = " << acc->sample_rate <<  " nb_samples =" << aframe->nb_samples << " pcm size = " << audio_buffersize <<  " ="<linesize[0] << endl; //输出音频的通道数和采样率
          data_count += audio_buffersize;
      
           av_samples_alloc_array_and_samples(&audio_data_buffer,
                            NULL, out_channels,
                            192000*2,//aframe->nb_samples,
                            out_sample_fmt, 1);
           int convert_size = swr_convert(au_convert_ctx,
                            audio_data_buffer,
                            192000,
                            (const uint8_t**)aframe->data,
                            aframe->nb_samples);
 
          pAudio_chunk = *audio_data_buffer;
          audio_len =  audio_buffersize;
          pAudio_pos = pAudio_chunk;
          while (audio_len > 0)
            SDL_Delay(1);
               
        }
        else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        {
          cout << "receive audio frame  error, need again" << endl;
          break; //接收到的数据无效 需要重新读入
        }
        else
        {
          cout << "avcodec_receive_frame audio error  code:" << ret << endl;
          return -3; //解码错误,可选择直接退出程序
        }
      }
    }
  }
  //再次解码输出解码器中的数据,否则会丢失部分数据
  int ret = 0;
  if (ret = avcodec_send_packet(acc, NULL) != 0)
  {
      cout << "send audio packet to decodec error" << endl;
      return -1;
  }
  while (ret >= 0)
  {
      ret = avcodec_receive_frame(acc, aframe);
      if (ret == 0)
      {
        int audio_buffersize = av_samples_get_buffer_size(NULL, acc->channels, acc->frame_size, acc->sample_fmt, 1); //获取音频数据大小
        cout << "decodec channels = " << acc->channels << "rate = " << acc->sample_rate << " nb_samples =" << aframe->nb_samples << "pcm size = " << audio_buffersize << endl;
        data_count += audio_buffersize;

        pAudio_chunk = (Uint8*)aframe->data;
        audio_len = audio_buffersize;
        pAudio_pos = pAudio_chunk;

        while (audio_len > 0)
          SDL_Delay(1);
      }
      else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
      {
        cout << "receive audio frame  error, need again" << endl;
        break; //接收到的数据无效 需要重新读入
      }
      else
      {
        cout << "avcodec_receive_frame audio error  code:" << ret << endl;
        return -3; //解码错误,可选择直接退出程序
      }
    }
  //退出SDL
  SDL_Quit();
  //释放资源
  av_packet_unref(&pkt);
  av_frame_free(&aframe);
  avcodec_free_context(&acc);
  avformat_close_input(&afc);
  return 0;
}

 

 

你可能感兴趣的:(FFMPEG,sdl,ffmpeg)