[4] FFmpeg + SDL2 audio player with audible noise

Source: Internet
Author: User
Tags data structures


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:


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.