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:
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 ();
}