diff --git a/.gitignore b/.gitignore index 8c1cb52..ed31b20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /build/sdlamp2 /build/sdlamp2.dSYM +*.mp3 +*.m4a + diff --git a/build.sh b/build.sh index 38b9e83..487f4d2 100755 --- a/build.sh +++ b/build.sh @@ -1,11 +1,15 @@ #!/bin/sh -pushd build +pushd build 2>&1 >/dev/null -gcc -Wall -O0 -ggdb3 \ +gcc -Wall -Wno-unused -O0 -ggdb3 \ -o sdlamp2 \ `sdl2-config --cflags --libs` \ + `pkgconf --cflags --libs libavformat` \ + `pkgconf --cflags --libs libavcodec` \ + `pkgconf --cflags --libs libavutil` \ + `pkgconf --cflags --libs libswresample` \ -lSDL2_image \ ../src/sdlamp2.c -popd +popd 2>&1 >/dev/null diff --git a/src/sdlamp2.c b/src/sdlamp2.c index 1827d0d..7d17b2d 100644 --- a/src/sdlamp2.c +++ b/src/sdlamp2.c @@ -1,25 +1,29 @@ +#include +#include +#include + #include "SDL.h" #include "SDL_image.h" -static SDL_Window *window = NULL; -static SDL_Renderer *renderer = NULL; +static SDL_Window* window = NULL; +static SDL_Renderer* renderer = NULL; static SDL_AudioDeviceID audio_device = 0; -static Uint8 *wavbuf = NULL; +static Uint8* wavbuf = NULL; static Uint32 wavlen = 0; static SDL_AudioSpec wavspec; -static SDL_AudioStream *stream = NULL; +static SDL_AudioStream* stream = NULL; // static SDL_bool paused = SDL_TRUE; static SDL_bool paused = SDL_FALSE; -static void panic_and_abort(const char *title, const char *text) { +static void panic_and_abort(const char* title, const char* text) { fprintf(stderr, "PANIC: %s ... %s\n", title, text); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, window); SDL_Quit(); exit(1); } -static SDL_bool load_audio_file(const char *fname) { +static SDL_bool load_audio_file(const char* fname) { SDL_FreeAudioStream(stream); stream = NULL; SDL_FreeWAV(wavbuf); @@ -27,33 +31,99 @@ static SDL_bool load_audio_file(const char *fname) { wavlen = 0; if (SDL_LoadWAV(fname, &wavspec, &wavbuf, &wavlen) == NULL) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load wav file!", - SDL_GetError(), window); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load wav file!", SDL_GetError(), + window); return SDL_FALSE; } - stream = SDL_NewAudioStream(wavspec.format, wavspec.channels, wavspec.freq, - AUDIO_F32, 2, 48000); + stream = SDL_NewAudioStream(wavspec.format, wavspec.channels, wavspec.freq, AUDIO_F32, 2, 48000); if (!stream) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Couldn't create audio stream!", SDL_GetError(), + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audio stream!", SDL_GetError(), window); SDL_FreeWAV(wavbuf); wavbuf = NULL; wavlen = 0; } - if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == - -1) { // FIXME(m): graceful handling. + if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) { // FIXME(m): graceful handling. panic_and_abort("Audio stream put failed!", SDL_GetError()); } - SDL_AudioStreamFlush(stream); // FIXME(m): error handling. + SDL_AudioStreamFlush(stream); // FIXME(m): error handling. SDL_PauseAudioDevice(audio_device, paused); return SDL_TRUE; } -int main(int argc, char **argv) { +static SDL_bool decode_audio() { + printf("libavutil version: %s\n", av_version_info()); + + // Trying to open and decode AAC / ALAC (.m4a file) with ffmpeg libraries + AVFormatContext* pFormatContext = avformat_alloc_context(); + if (avformat_open_input(&pFormatContext, "./build/music.m4a", NULL, NULL) != 0) { + printf("ERROR: could not open the file!\n"); + return SDL_FALSE; + } + printf("Format: %s\n", pFormatContext->iformat->long_name); + + avformat_find_stream_info(pFormatContext, NULL); + if (pFormatContext->nb_streams < 1) { + printf("ERROR: no valid streams found in file!\n"); + return SDL_FALSE; + } + + AVCodecParameters* pLocalCodecParameters = pFormatContext->streams[0]->codecpar; + if (pLocalCodecParameters->codec_type != AVMEDIA_TYPE_AUDIO) { + printf("ERROR: no audio stream found in file!\n"); + return SDL_FALSE; + } + + printf("Audio stream: %d channels, sample rate %d\n", + pLocalCodecParameters->ch_layout.nb_channels, pLocalCodecParameters->sample_rate); + + const AVCodec* pLocalCodec = avcodec_find_decoder(pLocalCodecParameters->codec_id); + printf("Codec: %s ID %d bit_rate %lld\n", pLocalCodec->long_name, pLocalCodec->id, + pLocalCodecParameters->bit_rate); + + AVCodecContext* pCodecContext = avcodec_alloc_context3(pLocalCodec); + avcodec_parameters_to_context(pCodecContext, pLocalCodecParameters); + avcodec_open2(pCodecContext, pLocalCodec, NULL); + + AVPacket* pPacket = av_packet_alloc(); + AVFrame* pFrame = av_frame_alloc(); + + SDL_FreeAudioStream(stream); + stream = NULL; + wavlen = 0; + + stream = SDL_NewAudioStream(AUDIO_F32, pLocalCodecParameters->ch_layout.nb_channels, + pLocalCodecParameters->sample_rate, AUDIO_F32, 2, 48000); + if (!stream) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audio stream!", SDL_GetError(), + window); + } + + while (av_read_frame(pFormatContext, pPacket) >= 0) { + if (!avcodec_send_packet(pCodecContext, pPacket)) { + avcodec_receive_frame(pCodecContext, pFrame); + if (pFrame->linesize[0] > 0) { + if (SDL_AudioStreamPut(stream, pFrame->data[0], pFrame->linesize[0]) == + -1) { // FIXME(m): graceful handling. + panic_and_abort("Audio stream put failed!", SDL_GetError()); + } + } + } + + // printf("Frame %c (%lld) pts %lld dts %lld\n", av_get_picture_type_char(pFrame->pict_type), + // pCodecContext->frame_num, pFrame->pts, pFrame->pkt_dts); + } + + SDL_AudioStreamFlush(stream); // FIXME(m): error handling. + SDL_PauseAudioDevice(audio_device, paused); + + return SDL_TRUE; +} + +int main(int argc, char** argv) { SDL_AudioSpec desired; SDL_bool running = SDL_TRUE; const SDL_Rect rewind_rect = {10, 10, 100, 100}; @@ -71,8 +141,8 @@ int main(int argc, char **argv) { panic_and_abort("SDL_Init failed!", SDL_GetError()); } - window = SDL_CreateWindow("SDLamp2", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, 640, 480, 0); + window = + SDL_CreateWindow("SDLamp2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0); if (!window) { panic_and_abort("SDL_CreateWindow failed!", SDL_GetError()); } @@ -94,15 +164,15 @@ int main(int argc, char **argv) { panic_and_abort("Could not open audio device!", SDL_GetError()); } - load_audio_file("music.wav"); + // load_audio_file("music.wav"); + decode_audio(); - SDL_Surface *controls_surface = IMG_Load("controls.png"); + SDL_Surface* controls_surface = IMG_Load("controls.png"); if (controls_surface == NULL) { panic_and_abort("Could not load controls asset!", SDL_GetError()); } - SDL_Texture *controls_texture = - SDL_CreateTextureFromSurface(renderer, controls_surface); + SDL_Texture* controls_texture = SDL_CreateTextureFromSurface(renderer, controls_surface); SDL_FreeSurface(controls_surface); if (controls_texture == NULL) { panic_and_abort("Could not load controls asset!", SDL_GetError()); @@ -113,28 +183,27 @@ int main(int argc, char **argv) { // Event loop while (SDL_PollEvent(&e)) { switch (e.type) { - case SDL_QUIT: - running = SDL_FALSE; - break; + case SDL_QUIT: + running = SDL_FALSE; + break; - case SDL_MOUSEBUTTONDOWN: { - const SDL_Point pt = {e.button.x, e.button.y}; - if (SDL_PointInRect(&pt, &rewind_rect)) { // Pressed the "rewind" button - SDL_ClearQueuedAudio(audio_device); - SDL_AudioStreamClear(stream); - if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == - -1) { // FIXME(m): graceful handling. - panic_and_abort("Audio stream put failed!", SDL_GetError()); + case SDL_MOUSEBUTTONDOWN: { + const SDL_Point pt = {e.button.x, e.button.y}; + if (SDL_PointInRect(&pt, + &rewind_rect)) { // Pressed the "rewind" button + SDL_ClearQueuedAudio(audio_device); + SDL_AudioStreamClear(stream); + if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) { // FIXME(m): graceful handling. + panic_and_abort("Audio stream put failed!", SDL_GetError()); + } + SDL_AudioStreamFlush(stream); // FIXME(m): error handling. + } else if (SDL_PointInRect(&pt, + &play_pause_rect)) { // Pressed the "pause" button + paused = paused ? SDL_FALSE : SDL_TRUE; + SDL_PauseAudioDevice(audio_device, paused); } - SDL_AudioStreamFlush(stream); // FIXME(m): error handling. - } else if (SDL_PointInRect( - &pt, - &play_pause_rect)) { // Pressed the "pause" button - paused = paused ? SDL_FALSE : SDL_TRUE; - SDL_PauseAudioDevice(audio_device, paused); + break; } - break; - } } } @@ -145,7 +214,7 @@ int main(int argc, char **argv) { const int new_bytes = SDL_min(bytes_remaining, 32 * 1024); static Uint8 converted_buffer[32 * 1024]; SDL_AudioStreamGet(stream, converted_buffer, - new_bytes); // FIXME(m): error handling. + new_bytes); // FIXME(m): error handling. SDL_QueueAudio(audio_device, converted_buffer, new_bytes); } } @@ -160,18 +229,14 @@ int main(int argc, char **argv) { SDL_RenderFillRect(renderer, &play_pause_rect); SDL_RenderFillRect(renderer, &fast_forward_rect); - SDL_RenderCopy(renderer, controls_texture, &rewind_symbol_rect, - &rewind_rect); + SDL_RenderCopy(renderer, controls_texture, &rewind_symbol_rect, &rewind_rect); SDL_RenderCopy(renderer, controls_texture, &stop_symbol_rect, &stop_rect); if (paused) { - SDL_RenderCopy(renderer, controls_texture, &play_symbol_rect, - &play_pause_rect); + SDL_RenderCopy(renderer, controls_texture, &play_symbol_rect, &play_pause_rect); } else { - SDL_RenderCopy(renderer, controls_texture, &pause_symbol_rect, - &play_pause_rect); + SDL_RenderCopy(renderer, controls_texture, &pause_symbol_rect, &play_pause_rect); } - SDL_RenderCopy(renderer, controls_texture, &fast_forward_symbol_rect, - &fast_forward_rect); + SDL_RenderCopy(renderer, controls_texture, &fast_forward_symbol_rect, &fast_forward_rect); SDL_RenderPresent(renderer); }