Decode audio stream using ffmpeg

This commit is contained in:
Alexander Kojevnikov 2010-07-01 22:47:25 +10:00
parent fd236e4b1a
commit eea89183d1
5 changed files with 88 additions and 4 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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 {

View File

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

View File

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