List of SDL2 articles
Introduction to SDL2
SDL2 event processing
SDL2 texture rendering
SDL2 PCM audio playback
FFmpeg+SDL2 video streaming
PCM audio playback has been completed before, this implementation is FFmpeg+SDL2 play audio stream in any video.
The overall process is similar to video streaming, but the SwrContext resampling structure needs to be understood
Resampling structure is to change the sampling rate, sample format, number of tracks and other parameters of audio to output according to our expectations. Of course, the original audio parameters do not meet our needs. For example, when FFMPEG decodes audio, different audio sources have different formats, sampling rate and so on. These parameters in the decoded data will also be inconsistent. If we need to use the decoded audio data for other operations, and there will be a lot of extra work due to the inconsistency of these parameters, it will be much more convenient to resampling them directly to obtain the audio parameters we have formulated.
By resampling, you can adjust the sample rate, sample format, and channel layout.
SwrContext is a common function
swr_alloc
// Apply a SwrContext structure
struct SwrContext *swr_alloc(void);
Copy the code
swr_init
// Use this function to initialize the SwrContext structure when the relevant parameters are set
int swr_init(struct SwrContext *s);
Copy the code
swr_alloc_set_opts
// Allocate the SwrContext and set/reset the usual parameters. Parameters include input and output parameters such as Sample Rate, sample format, and Channel layoutFunction prototype:struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
int64_t out_ch_layout,
enum AVSampleFormat out_sample_fmt,
int out_sample_rate,
int64_t in_ch_layout,
enum AVSampleFormat in_sample_fmt,
int in_sample_rate,
int log_offset,
void *log_ctx);
Copy the code
swr_convert
// Convert the input audio according to the defined parameters and output it
int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
const uint8_t **in , int in_count);
Copy the code
swr_free
// Release the SwrContext structure and set it to NULL;
void swr_free(struct SwrContext **s);
Copy the code
The sample code
//
// Created by Liu Wei on 2019/4/26
//
#include <stdio.h>
#include <SDL_types.h>
#include "SDL.h"
#include "libswresample/swresample.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;
#define MAX_AUDIO_FRAME_SIZE 19200
// The audio device calls this callback when it needs more data
void read_audio_data(void *udata, Uint8 *stream, int len) {
// First use SDL_memset() to set the data in stream to 0
SDL_memset(stream, 0, len);
if (audio_len == 0)
return;
len = (len > audio_len ? audio_len : len);
SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
audio_pos += len;
audio_len -= len;
}
int WinMain(int argc, char *argv[]) {
char *file = "C:\\Users\\lenovo\\Desktop\\1080p.mov";
AVFormatContext *pFormatCtx = NULL;
int i, audioStream = - 1;
AVCodecParameters *pCodecParameters = NULL;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL;
AVPacket *packet;
uint8_t *out_buffer;
int64_t in_channel_layout;
struct SwrContext *au_convert_ctx;
if (avformat_open_input(&pFormatCtx, file, NULL.NULL) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open video file!");
return - 1; // Couldn't open file
}
audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, - 1.- 1.NULL.0);
if (audioStream == - 1) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Din't find a video stream!");
return - 1;// Didn't find a video stream
}
// Audio stream parameters
pCodecParameters = pFormatCtx->streams[audioStream]->codecpar;
// Get the decoder
pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
if (pCodec == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported codec! \n");
return - 1; // Codec not found
}
// Copy context
pCodecCtx = avcodec_alloc_context3(pCodec);
if(avcodec_parameters_to_context(pCodecCtx, pCodecParameters) ! =0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't copy codec context");
return - 1;// Error copying codec context
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open decoder! \n");
return - 1; // Could not open codec
}
packet = (AVPacket *) av_malloc(sizeof(AVPacket));
av_init_packet(packet);
pFrame = av_frame_alloc();
uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;// Output channel
int out_nb_samples = 1024;
enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;// Output format S16
int out_sample_rate = 44100;
int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
out_buffer = (uint8_t *) av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
//Init
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return - 1;
}
SDL_AudioSpec spec;
spec.freq = out_sample_rate;
spec.format = AUDIO_S16SYS;
spec.channels = out_channels;
spec.silence = 0;
spec.samples = out_nb_samples;
spec.callback = read_audio_data;
spec.userdata = pCodecCtx;
if (SDL_OpenAudio(&spec, NULL) < 0) {
printf("can't open audio.\n");
return - 1;
}
in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);
printf("in_channel_layout --->%d\n", in_channel_layout);
au_convert_ctx = swr_alloc();
au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0.NULL);
swr_init(au_convert_ctx);
SDL_PauseAudio(0);
while (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet->stream_index == audioStream) {
avcodec_send_packet(pCodecCtx, packet);
while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {
swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **) pFrame->data,pFrame->nb_samples); // Convert audio
}
audio_chunk = (Uint8 *) out_buffer;
audio_len = out_buffer_size;
audio_pos = audio_chunk;
while (audio_len > 0) {
SDL_Delay(1);// Delay playback
}
}
av_packet_unref(packet);
}
swr_free(&au_convert_ctx);
SDL_Quit();
return 0;
}
Copy the code
GitHub-SimplePlayer- Audio_player