spek

Acoustic spectrum analyser
git clone http://git.hanabi.in/repos/spek.git
Log | Files | Refs | README

commit eea89183d1fc82745310d8891138806fb090a8cb
parent fd236e4b1a7807003d5168406ed6783c75be0f50
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date:   Thu,  1 Jul 2010 22:47:25 +1000

Decode audio stream using ffmpeg

Diffstat:
Msrc/spek-audio.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/spek-audio.h | 26+++++++++++++++++++++++---
Msrc/spek-pipeline.vala | 3+++
Msrc/spek-spectrogram.vala | 2+-
Mvapi/spek-audio.vapi | 3+++
5 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/src/spek-audio.c b/src/spek-audio.c @@ -22,6 +22,7 @@ void spek_audio_init () { avcodec_init (); + /* TODO: register only audio decoders */ av_register_all (); } @@ -70,13 +71,64 @@ SpekAudioContext * spek_audio_open (const char *file_name) { cx->bits_per_sample = cx->codec_context->bits_per_coded_sample; } cx->channels = cx->codec_context->channels; + cx->buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2; if (avcodec_open (cx->codec_context, cx->codec) < 0) { cx->error = _("Cannot open decoder"); return cx; } + av_init_packet (&cx->packet); + cx->offset = 0; return cx; } +gint spek_audio_read (SpekAudioContext *cx, guint8 *buffer) { + gint buffer_size; + gint len; + gint res; + + if (cx->error) { + return -1; + } + + for (;;) { + while (cx->packet.size > 0) { + buffer_size = cx->buffer_size; + len = avcodec_decode_audio3 ( + cx->codec_context, (int16_t *) buffer, &buffer_size, &cx->packet); + if (len < 0) { + /* Error, skip the frame. */ + cx->packet.size = 0; + break; + } + cx->packet.data += len; + cx->packet.size -= len; + cx->offset += len; + if (buffer_size <= 0) { + /* No data yet, get more frames */ + continue; + } + /* We have data, return it and come back for more later */ + return buffer_size; + } + if (cx->packet.data) { + cx->packet.data -= cx->offset; + cx->packet.size += cx->offset; + cx->offset = 0; + av_free_packet (&cx->packet); + } + while ((res = av_read_frame (cx->format_context, &cx->packet)) >= 0) { + if (cx->packet.stream_index == cx->audio_stream) { + break; + } + av_free_packet (&cx->packet); + } + if (res < 0) { + /* End of file or error. */ + return 0; + } + } +} + void spek_audio_close (SpekAudioContext *cx) { if (cx->file_name != NULL) { g_free (cx->file_name); @@ -84,6 +136,12 @@ void spek_audio_close (SpekAudioContext *cx) { if (cx->codec_name != NULL) { g_free (cx->codec_name); } + if (cx->packet.data) { + cx->packet.data -= cx->offset; + cx->packet.size += cx->offset; + cx->offset = 0; + av_free_packet (&cx->packet); + } if (cx->codec_context != NULL) { avcodec_close (cx->codec_context); } diff --git a/src/spek-audio.h b/src/spek-audio.h @@ -24,13 +24,15 @@ #include <libavcodec/avcodec.h> typedef struct { + /* Internal data */ AVFormatContext *format_context; gint audio_stream; AVCodecContext *codec_context; AVCodec *codec; + AVPacket packet; + gint offset; - /* Exposed properties - */ + /* Exposed properties */ gchar *file_name; gchar *codec_name; gchar *error; @@ -38,10 +40,28 @@ typedef struct { gint sample_rate; gint bits_per_sample; gint channels; + gint buffer_size; /* minimum buffer size for spek_audio_read() */ } SpekAudioContext; +/* Initialise FFmpeg, should be called once on start up */ void spek_audio_init (); -SpekAudioContext * spek_audio_open (const char *file_name); + +/* Open the file, check if it has an audio stream which can be decoded. + * On error, initialises the `error` field in the returned context. + */ +SpekAudioContext * spek_audio_open (const gchar *file_name); + +/* Read and decode the opened audio stream. + * Returns -1 on error, 0 if there's nothing left to read + * or the number of bytes decoded into the buffer. + * The buffer must be allocated (and later freed) by the caller, + * minimum size is `buffer_size`. + */ +gint spek_audio_read (SpekAudioContext *cx, guint8 *buffer); + +/* Closes the file opened with spek_audio_open, + * frees all allocated buffers and the context + */ void spek_audio_close (SpekAudioContext *cx); #endif diff --git a/src/spek-pipeline.vala b/src/spek-pipeline.vala @@ -50,6 +50,9 @@ namespace Spek { // TRANSLATORS: first %s is the error message, second %s is stream description. description = _("%s: %s").printf (cx.error, description); } + + var buffer = new uint8[cx.buffer_size]; + while (cx.read (buffer) > 0); } public string file_name { diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala @@ -65,7 +65,7 @@ namespace Spek { // TODO var pipeline = new Pipeline (file_name); - print ("%s:\n%s\n", file_name, pipeline.description); + print ("\n%s:\n%s\n", file_name, pipeline.description); start (); } diff --git a/vapi/spek-audio.vapi b/vapi/spek-audio.vapi @@ -10,9 +10,12 @@ namespace Spek.Audio { public int sample_rate; public int bits_per_sample; public int channels; + public int buffer_size; [CCode (cname = "spek_audio_open")] public Context (string file_name); + [CCode (cname = "spek_audio_read")] + public int read ([CCode (array_length = false)] uint8[] buffer); } public static void init (); }