mirror of
https://github.com/alexkay/spek.git
synced 2025-06-19 16:24:15 +03:00
Decode audio stream using ffmpeg
This commit is contained in:
parent
fd236e4b1a
commit
eea89183d1
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user