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 () {
|
void spek_audio_init () {
|
||||||
avcodec_init ();
|
avcodec_init ();
|
||||||
|
/* TODO: register only audio decoders */
|
||||||
av_register_all ();
|
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->bits_per_sample = cx->codec_context->bits_per_coded_sample;
|
||||||
}
|
}
|
||||||
cx->channels = cx->codec_context->channels;
|
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) {
|
if (avcodec_open (cx->codec_context, cx->codec) < 0) {
|
||||||
cx->error = _("Cannot open decoder");
|
cx->error = _("Cannot open decoder");
|
||||||
return cx;
|
return cx;
|
||||||
}
|
}
|
||||||
|
av_init_packet (&cx->packet);
|
||||||
|
cx->offset = 0;
|
||||||
return cx;
|
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) {
|
void spek_audio_close (SpekAudioContext *cx) {
|
||||||
if (cx->file_name != NULL) {
|
if (cx->file_name != NULL) {
|
||||||
g_free (cx->file_name);
|
g_free (cx->file_name);
|
||||||
@ -84,6 +136,12 @@ void spek_audio_close (SpekAudioContext *cx) {
|
|||||||
if (cx->codec_name != NULL) {
|
if (cx->codec_name != NULL) {
|
||||||
g_free (cx->codec_name);
|
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) {
|
if (cx->codec_context != NULL) {
|
||||||
avcodec_close (cx->codec_context);
|
avcodec_close (cx->codec_context);
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,15 @@
|
|||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/* Internal data */
|
||||||
AVFormatContext *format_context;
|
AVFormatContext *format_context;
|
||||||
gint audio_stream;
|
gint audio_stream;
|
||||||
AVCodecContext *codec_context;
|
AVCodecContext *codec_context;
|
||||||
AVCodec *codec;
|
AVCodec *codec;
|
||||||
|
AVPacket packet;
|
||||||
|
gint offset;
|
||||||
|
|
||||||
/* Exposed properties
|
/* Exposed properties */
|
||||||
*/
|
|
||||||
gchar *file_name;
|
gchar *file_name;
|
||||||
gchar *codec_name;
|
gchar *codec_name;
|
||||||
gchar *error;
|
gchar *error;
|
||||||
@ -38,10 +40,28 @@ typedef struct {
|
|||||||
gint sample_rate;
|
gint sample_rate;
|
||||||
gint bits_per_sample;
|
gint bits_per_sample;
|
||||||
gint channels;
|
gint channels;
|
||||||
|
gint buffer_size; /* minimum buffer size for spek_audio_read() */
|
||||||
} SpekAudioContext;
|
} SpekAudioContext;
|
||||||
|
|
||||||
|
/* Initialise FFmpeg, should be called once on start up */
|
||||||
void spek_audio_init ();
|
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);
|
void spek_audio_close (SpekAudioContext *cx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -50,6 +50,9 @@ namespace Spek {
|
|||||||
// TRANSLATORS: first %s is the error message, second %s is stream description.
|
// TRANSLATORS: first %s is the error message, second %s is stream description.
|
||||||
description = _("%s: %s").printf (cx.error, description);
|
description = _("%s: %s").printf (cx.error, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buffer = new uint8[cx.buffer_size];
|
||||||
|
while (cx.read (buffer) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string file_name {
|
public string file_name {
|
||||||
|
@ -65,7 +65,7 @@ namespace Spek {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
var pipeline = new Pipeline (file_name);
|
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 ();
|
start ();
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,12 @@ namespace Spek.Audio {
|
|||||||
public int sample_rate;
|
public int sample_rate;
|
||||||
public int bits_per_sample;
|
public int bits_per_sample;
|
||||||
public int channels;
|
public int channels;
|
||||||
|
public int buffer_size;
|
||||||
|
|
||||||
[CCode (cname = "spek_audio_open")]
|
[CCode (cname = "spek_audio_open")]
|
||||||
public Context (string file_name);
|
public Context (string file_name);
|
||||||
|
[CCode (cname = "spek_audio_read")]
|
||||||
|
public int read ([CCode (array_length = false)] uint8[] buffer);
|
||||||
}
|
}
|
||||||
public static void init ();
|
public static void init ();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user