Date: 2016.10.4
Author: isshe
Github:github.com/isshe
E-mail: i.sshe@outlook.com
Platform: ubuntu16.04 64bit
preamble
FFmpeg decodes the data into PCM. SDL outputs the PCM data.
1. Program Flowchart
Initialize to find the appropriate decoder, open the decoder to open the audio device (available sdl_openaudiodriver () instead), here will be the thread run callback function. Sets the relevant parameters. The 2,3,4 parameter is output and 5,6,7 is the input parameter. Read a avpacket. Decoding. Make transformations such as some format. Output.
Example Code
* The intent of this program is:
* Decode the data into the buffer and use the global variable to point to the buffer.
* The callback function (the thread runs at Sdl_audioopen () call) sends the buffer data to stream and then makes a sound.
* In a child thread, the callback function is called again and again, taking away the buffer data.
* While the main thread decodes the data in a loop, it is placed in the buffer and waits if the buffer has data.
* This code output audio has a noise, has not been corrected.
* Program is to refer to the code of the Thor changed. Would have been to run his code, there is this problem, changed the Out_buffer also have. Just change this as you think, or it's the problem.
* Places to NOTE:
* The first parameter of the callback function corresponds to the userdata in the SDL_AUDIOSPEC structure. (a AVCODECCONTEXT structure is generally transmitted.)
* 192000 represents the highest sampling frequency for 192kHz, general audio usage. (Audio related knowledge See previous blog post, and degrees Niang)
* Three global variables are used in callback functions, flags buffer locations, and so on.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __STDC_CONSTANT_MACROS // ffmpeg required
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec / avcodec.h>
#include <libavformat / avformat.h>
#include <libswresample / swresample.h>
#include <SDL2 / SDL.h>
#ifdef __cplusplus
}
#endif
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
#define FILE_NAME "/home/isshe/Music/WavinFlag.aac"
#define ERR_STREAM stderr
#define OUT_SAMPLE_RATE 44100
static uint8_t * audio_buf;
static int audio_len;
static long long audio_buf_index;
void get_file_name (char * filename, int argc, char * argv []);
void open_and_find_inputfile_info (AVFormatContext ** pformat_ctx, char * filename);
int get_audio_stream_index (AVFormatContext * pformat_ctx);
void fill_audio (void * udata, Uint8 * stream, int len);
int main (int argc, char * argv [])
{
AVFrame out_frame;
AVFormatContext * pformat_ctx = NULL;
int audio_stream = 0;
AVCodecContext * pcodec_ctx = NULL;
AVCodec * pcodec = NULL;
AVPacket * ppacket = NULL; //!
AVFrame * pframe = NULL;
uint8_t * out_buffer = NULL; //
int decode_len = 0;
uint32_t len = 0;
int got_picture = 0;
int index = 0;
int64_t in_channel_layout = 0;
struct SwrContext * swr_ctx = NULL;
char filename [256] = FILE_NAME;
FILE * output_fp = NULL;
int convert_len = 0;
int data_size = 0;
// SDL
SDL_AudioSpec wanted_spec;
get_file_name (filename, argc, argv);
fprintf (ERR_STREAM, "file name:% s \ n", filename);
// about ffmpeg
// init
av_register_all ();
// SDL
if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
{
fprintf (ERR_STREAM, "Couldn't init SDL:% s \ n", SDL_GetError ());
exit (-1);
}
// open input file
// pformat_ctx = avformat_alloc_context ();
open_and_find_inputfile_info (& pformat_ctx, filename);
av_dump_format (pformat_ctx, 0, filename, false); // Output file information, a very useful function
audio_stream = get_audio_stream_index (pformat_ctx);
pcodec_ctx = pformat_ctx-> streams [audio_stream]-> codec;
// find a corresponding decoder
pcodec = avcodec_find_decoder (pcodec_ctx-> codec_id);
if (pcodec == NULL)
{
fprintf (ERR_STREAM, "Codec not found \ n");
exit (-1);
}
out_buffer = (uint8_t *) av_malloc (MAX_AUDIO_FRAME_SIZE * 2);
audio_buf = out_buffer;
pframe = av_frame_alloc ();
// SDL_AudioSpec, setting parameters for turning on the audio device
// nb_samples: AAC-1024 MP3-1152
// AV_CH_LAYOUT_STEREO: stereo
// Sample format. In an enum
// Sampling rate: 44100, there are 44100 samples per second.
// Number of channels: 1-mono, 2-stereo, 4-quad, 6 -...
wanted_spec.freq = pcodec_ctx-> sample_rate; // sample rate 44100
wanted_spec.format = AUDIO_S16SYS; // Sample format
wanted_spec.channels = pcodec_ctx-> channels; // 1-mono, 2-stereo
wanted_spec.silence = 0; // silence value
wanted_spec.samples = 1024; // Number of output samples
wanted_spec.callback = fill_audio; // callback function
wanted_spec.userdata = pcodec_ctx; // user data
// Open the audio device, return 0 if successful, use SDL_OpenAudioDriver instead
if (SDL_OpenAudio (& wanted_spec, NULL) <0)
{
fprintf (ERR_STREAM, "Couldn't open Audio \ n");
exit (-1);
}
// Set the following parameters for swr_alloc_set_opts after decoding.
out_frame.format = AV_SAMPLE_FMT_S16;
out_frame.sample_rate = wanted_spec.freq;
out_frame.channels = wanted_spec.channels;
out_frame.channel_layout = av_get_default_channel_layout (wanted_spec.channels);
// Open the decoder
if (avcodec_open2 (pcodec_ctx, pcodec, NULL) <0)
{
fprintf (ERR_STREAM, "Couldn't open decoder \ n");
exit (-1);
}
fprintf (ERR_STREAM, "Bit rate:% d \ n", pformat_ctx-> bit_rate);
fprintf (ERR_STREAM, "Decoder Name =% s \ n", pcodec_ctx-> codec-> long_name);
fprintf (ERR_STREAM, "Channels:% d \ n", pcodec_ctx-> channels);
fprintf (ERR_STREAM, "Sample per Second:% d \ n", pcodec_ctx-> sample_rate);
ppacket = (AVPacket *) av_malloc (sizeof (AVPacket));
av_init_packet (ppacket);
// play
SDL_PauseAudio (0); // ???
while (av_read_frame (pformat_ctx, ppacket)> = 0)
{
if (ppacket-> stream_index == audio_stream)
{
decode_len = avcodec_decode_audio4 (pcodec_ctx, pframe, & got_picture, ppacket);
if (decode_len <0)
{
fprintf (ERR_STREAM, "Couldn't decode audio frame \ n");
continue; //
}
if (got_picture)
{
if (swr_ctx! = NULL)
{
swr_free (& swr_ctx);
swr_ctx = NULL;
}
swr_ctx = swr_alloc_set_opts (NULL, out_frame.channel_layout,(AVSampleFormat) out_frame.format, out_frame.sample_rate,
pframe-> channel_layout, (AVSampleFormat) pframe-> format,
pframe-> sample_rate, 0, NULL);
//initialization
if (swr_ctx == NULL || swr_init (swr_ctx) <0)
{
fprintf (ERR_STREAM, "swr_init error \ n");
break;
}
convert_len = swr_convert (swr_ctx, & audio_buf,
MAX_AUDIO_FRAME_SIZE,
(const uint8_t **) pframe-> data,
pframe-> nb_samples);
}
printf ("decode len =% d, convert_len =% d \ n", decode_len, convert_len);
// Back to the buffer head and continue playing data
audio_buf_index = 0;
audio_buf = out_buffer;
// number of channels * length of conversion * length of each sample
audio_len = out_frame.channels * convert_len * av_get_bytes_per_sample ((AVSampleFormat) out_frame.format);
while (audio_len> 0)
{
SDL_Delay (1); // Stop for 1 microsecond
}
}
av_init_packet (ppacket);
// av_free_packet (ppacket);
}
swr_free (& swr_ctx);
SDL_CloseAudio ();
SDL_Quit ();
fclose (output_fp);
av_free (out_buffer);
avcodec_close (pcodec_ctx);
avformat_close_input (& pformat_ctx);
return 0;
}
void fill_audio (void * udata, Uint8 * stream, int len)
{
SDL_memset (stream, 0, len);
if (audio_len == 0)
{
return;
}
len = len> audio_len? audio_len: len;
SDL_MixAudio (stream, (uint8_t *) audio_buf + audio_buf_index, len, SDL_MIX_MAXVOLUME);
audio_buf_index + = len;
audio_len-= len;
stream + = len;
}
void get_file_name (char * filename, int argc, char * argv [])
{
if (argc == 2)
{
memcpy (filename, argv [1], strlen (argv [1]) + 1);
}
else if (argc> 2)
{
fprintf (ERR_STREAM, "Usage: ./*.out audio_file.mp3 \ n");
exit (-1);
}
}
void open_and_find_inputfile_info (AVFormatContext ** pformat_ctx, char * filename)
{
if (avformat_open_input (pformat_ctx, filename, NULL, NULL)! = 0)
{
fprintf (ERR_STREAM, "Couldn 'open input file \ n");
exit (-1);
}
if (avformat_find_stream_info (* pformat_ctx, NULL) <0)
{
fprintf (ERR_STREAM, "Couldn 'find stream info \ n");
exit (-1);
}
}
int get_audio_stream_index (AVFormatContext * pformat_ctx)
{
int i = 0;
int audio_stream = -1;
for (i = 0; i <pformat_ctx-> nb_streams; i ++)
{
if (pformat_ctx-> streams [i]-> codec-> codec_type == AVMEDIA_TYPE_AUDIO)
{
audio_stream = i;
break;
}
}
if (audio_stream == -1)
{
fprintf (ERR_STREAM, "Didn't find audio stream \ n");
exit (-1);
}
return audio_stream;
}
compiling Makefile
CC = g++
LIBDIR = -L/usr/local/lib
INCDIR = -I/usr/local/include/ -I../common/ -I./
OPTION = -O2 -Wall -g
LIB_FFMPEG = -lavformat -lavcodec -lavformat -lavutil -lswresample -lswscale
LIB_SDL2 = -lSDL2 -lSDL2main
LIB_OTHER = -lx264 -lx265 -lvpx -lmp3lame -lopus -lfdk-aac -lX11 -lva -lvdpau -lva-drm -lva-x11 -lvorbisenc -lvorbis -ltheoraenc -ltheoradec -ldl -lm -lpthread -lz
ffmpeg_decoder:
$(CC) audio_player_v1.0.c -o audio_player_v1.0.out $(LIBDIR) $(INCDIR) $(OPTION) $(LIB_FFMPEG) $(LIB_OTHER) $(LIB_SDL2)
ResultsThe audio of the ubuntu16.04 output is noisy. Windows did not hear a murmur. Windows uses VS2010 to run. Specific operating methods, see the Thor video.
References
Raytheon Blog: http://blog.csdn.net/leixiaohua1020/article/details/38979615?locationNum=2 code Download
Refer to Thor's: http://download.csdn.net/detail/i_scream_/9645560
Self-changed: http://download.csdn.net/detail/i_scream_/ 9645676 expand (To add) ffmpeg video-related functions: FFmpeg video-related data structures: FFmpeg audio-related functions: FFmpeg audio-related data structures: SDL video-related functions: SDL video-related data structures: SDL Audio-related functions: SDL audio-related data structure: