Semi working version

This commit is contained in:
Michael Smith 2026-01-28 13:37:34 +01:00
parent 333ab8f82d
commit a80bd0c480
3 changed files with 125 additions and 53 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
/build/sdlamp2 /build/sdlamp2
/build/sdlamp2.dSYM /build/sdlamp2.dSYM
*.mp3
*.m4a

View File

@ -1,11 +1,15 @@
#!/bin/sh #!/bin/sh
pushd build pushd build 2>&1 >/dev/null
gcc -Wall -O0 -ggdb3 \ gcc -Wall -Wno-unused -O0 -ggdb3 \
-o sdlamp2 \ -o sdlamp2 \
`sdl2-config --cflags --libs` \ `sdl2-config --cflags --libs` \
`pkgconf --cflags --libs libavformat` \
`pkgconf --cflags --libs libavcodec` \
`pkgconf --cflags --libs libavutil` \
`pkgconf --cflags --libs libswresample` \
-lSDL2_image \ -lSDL2_image \
../src/sdlamp2.c ../src/sdlamp2.c
popd popd 2>&1 >/dev/null

View File

@ -1,25 +1,29 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include "SDL.h" #include "SDL.h"
#include "SDL_image.h" #include "SDL_image.h"
static SDL_Window *window = NULL; static SDL_Window* window = NULL;
static SDL_Renderer *renderer = NULL; static SDL_Renderer* renderer = NULL;
static SDL_AudioDeviceID audio_device = 0; static SDL_AudioDeviceID audio_device = 0;
static Uint8 *wavbuf = NULL; static Uint8* wavbuf = NULL;
static Uint32 wavlen = 0; static Uint32 wavlen = 0;
static SDL_AudioSpec wavspec; 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_TRUE;
static SDL_bool paused = SDL_FALSE; 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); fprintf(stderr, "PANIC: %s ... %s\n", title, text);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, window); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, window);
SDL_Quit(); SDL_Quit();
exit(1); exit(1);
} }
static SDL_bool load_audio_file(const char *fname) { static SDL_bool load_audio_file(const char* fname) {
SDL_FreeAudioStream(stream); SDL_FreeAudioStream(stream);
stream = NULL; stream = NULL;
SDL_FreeWAV(wavbuf); SDL_FreeWAV(wavbuf);
@ -27,24 +31,21 @@ static SDL_bool load_audio_file(const char *fname) {
wavlen = 0; wavlen = 0;
if (SDL_LoadWAV(fname, &wavspec, &wavbuf, &wavlen) == NULL) { if (SDL_LoadWAV(fname, &wavspec, &wavbuf, &wavlen) == NULL) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load wav file!", SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load wav file!", SDL_GetError(),
SDL_GetError(), window); window);
return SDL_FALSE; return SDL_FALSE;
} }
stream = SDL_NewAudioStream(wavspec.format, wavspec.channels, wavspec.freq, stream = SDL_NewAudioStream(wavspec.format, wavspec.channels, wavspec.freq, AUDIO_F32, 2, 48000);
AUDIO_F32, 2, 48000);
if (!stream) { if (!stream) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audio stream!", SDL_GetError(),
"Couldn't create audio stream!", SDL_GetError(),
window); window);
SDL_FreeWAV(wavbuf); SDL_FreeWAV(wavbuf);
wavbuf = NULL; wavbuf = NULL;
wavlen = 0; wavlen = 0;
} }
if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) { // FIXME(m): graceful handling.
-1) { // FIXME(m): graceful handling.
panic_and_abort("Audio stream put failed!", SDL_GetError()); panic_and_abort("Audio stream put failed!", SDL_GetError());
} }
SDL_AudioStreamFlush(stream); // FIXME(m): error handling. SDL_AudioStreamFlush(stream); // FIXME(m): error handling.
@ -53,7 +54,76 @@ static SDL_bool load_audio_file(const char *fname) {
return SDL_TRUE; 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_AudioSpec desired;
SDL_bool running = SDL_TRUE; SDL_bool running = SDL_TRUE;
const SDL_Rect rewind_rect = {10, 10, 100, 100}; 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()); panic_and_abort("SDL_Init failed!", SDL_GetError());
} }
window = SDL_CreateWindow("SDLamp2", SDL_WINDOWPOS_UNDEFINED, window =
SDL_WINDOWPOS_UNDEFINED, 640, 480, 0); SDL_CreateWindow("SDLamp2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
if (!window) { if (!window) {
panic_and_abort("SDL_CreateWindow failed!", SDL_GetError()); 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()); 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) { if (controls_surface == NULL) {
panic_and_abort("Could not load controls asset!", SDL_GetError()); panic_and_abort("Could not load controls asset!", SDL_GetError());
} }
SDL_Texture *controls_texture = SDL_Texture* controls_texture = SDL_CreateTextureFromSurface(renderer, controls_surface);
SDL_CreateTextureFromSurface(renderer, controls_surface);
SDL_FreeSurface(controls_surface); SDL_FreeSurface(controls_surface);
if (controls_texture == NULL) { if (controls_texture == NULL) {
panic_and_abort("Could not load controls asset!", SDL_GetError()); panic_and_abort("Could not load controls asset!", SDL_GetError());
@ -119,16 +189,15 @@ int main(int argc, char **argv) {
case SDL_MOUSEBUTTONDOWN: { case SDL_MOUSEBUTTONDOWN: {
const SDL_Point pt = {e.button.x, e.button.y}; const SDL_Point pt = {e.button.x, e.button.y};
if (SDL_PointInRect(&pt, &rewind_rect)) { // Pressed the "rewind" button if (SDL_PointInRect(&pt,
&rewind_rect)) { // Pressed the "rewind" button
SDL_ClearQueuedAudio(audio_device); SDL_ClearQueuedAudio(audio_device);
SDL_AudioStreamClear(stream); SDL_AudioStreamClear(stream);
if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) { // FIXME(m): graceful handling.
-1) { // FIXME(m): graceful handling.
panic_and_abort("Audio stream put failed!", SDL_GetError()); panic_and_abort("Audio stream put failed!", SDL_GetError());
} }
SDL_AudioStreamFlush(stream); // FIXME(m): error handling. SDL_AudioStreamFlush(stream); // FIXME(m): error handling.
} else if (SDL_PointInRect( } else if (SDL_PointInRect(&pt,
&pt,
&play_pause_rect)) { // Pressed the "pause" button &play_pause_rect)) { // Pressed the "pause" button
paused = paused ? SDL_FALSE : SDL_TRUE; paused = paused ? SDL_FALSE : SDL_TRUE;
SDL_PauseAudioDevice(audio_device, paused); SDL_PauseAudioDevice(audio_device, paused);
@ -160,18 +229,14 @@ int main(int argc, char **argv) {
SDL_RenderFillRect(renderer, &play_pause_rect); SDL_RenderFillRect(renderer, &play_pause_rect);
SDL_RenderFillRect(renderer, &fast_forward_rect); SDL_RenderFillRect(renderer, &fast_forward_rect);
SDL_RenderCopy(renderer, controls_texture, &rewind_symbol_rect, SDL_RenderCopy(renderer, controls_texture, &rewind_symbol_rect, &rewind_rect);
&rewind_rect);
SDL_RenderCopy(renderer, controls_texture, &stop_symbol_rect, &stop_rect); SDL_RenderCopy(renderer, controls_texture, &stop_symbol_rect, &stop_rect);
if (paused) { if (paused) {
SDL_RenderCopy(renderer, controls_texture, &play_symbol_rect, SDL_RenderCopy(renderer, controls_texture, &play_symbol_rect, &play_pause_rect);
&play_pause_rect);
} else { } else {
SDL_RenderCopy(renderer, controls_texture, &pause_symbol_rect, SDL_RenderCopy(renderer, controls_texture, &pause_symbol_rect, &play_pause_rect);
&play_pause_rect);
} }
SDL_RenderCopy(renderer, controls_texture, &fast_forward_symbol_rect, SDL_RenderCopy(renderer, controls_texture, &fast_forward_symbol_rect, &fast_forward_rect);
&fast_forward_rect);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }