summaryrefslogtreecommitdiff
path: root/decoders/decoder_mpg123.c
blob: 9782f5bd09473450dd6d70eeb33626f5d63aafd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "decoder.h"

#include <mpg123.h>
#include <stdio.h>

static gboolean mpg123_decoder_init(struct decoder *decoder) {
	mpg123_handle *handle;

	int error;
	mpg123_init();

	handle = mpg123_new("generic", &error);
	if(error) {
		g_warning("Error: %s", mpg123_plain_strerror(error));
		return FALSE;
	}

	error = mpg123_open_feed(handle);
	if(error) {
		g_warning("Error: %s", mpg123_plain_strerror(error));
	}

	/* force format for now */
	mpg123_format_none(handle);
	mpg123_format(handle, 44100, 2, MPG123_ENC_SIGNED_16);

	decoder->data = handle;

	return TRUE;
}

static gssize mpg123_decoder_decode(struct decoder *decoder, GInputStream *input,
		GOutputStream *output, GError **error) {
	mpg123_handle *handle = decoder->data;
	gssize size;
	int ret;
	const int inbuf_size = 0x400*8;
	const int outbuf_size = 0x400*8;
	unsigned char inbuf[inbuf_size];
	unsigned char outbuf[inbuf_size];

	gsize inbuf_read = g_input_stream_read(input, inbuf, inbuf_size, NULL, NULL);

	if(mpg123_feed(handle, inbuf, inbuf_read) != MPG123_OK) {
		g_debug("asdfasdf");
		*error = g_error_new(decoder_quark(), DECODER_CODE_ERROR, mpg123_strerror(handle));
		return -1;
	}

	ret = mpg123_read(handle, outbuf, outbuf_size, (size_t*)&size);

	if(ret == MPG123_NEW_FORMAT) {
		long rate;
		int channels, enc;
		mpg123_getformat(handle, &rate, &channels, &enc);
		g_debug("New format: %li Hz, %i channels, encoding value %i", rate, channels, enc);
		ret = mpg123_read(handle, outbuf, outbuf_size, (size_t*)&size);
		decoder->rate = rate;
		/* TODO: mpg123 uses native byte order, add endian check here */
		/* assuming little endian for now... */
		switch(enc) {
			case MPG123_ENC_SIGNED_16:
				decoder->format = AUDIO_FORMAT_S16LE;
				break;
			default:
				*error = g_error_new(decoder_quark(), DECODER_CODE_ERROR, g_strdup("unknown audio format"));
				return -1;
		}
		decoder->channels = channels;
	}

	if(ret != MPG123_OK && ret != MPG123_DONE && ret != MPG123_NEW_FORMAT
			&& ret != MPG123_NEED_MORE) {
		*error = g_error_new(decoder_quark(), DECODER_CODE_ERROR, mpg123_plain_strerror(ret));
		return -1;
	}

	if(size == 0) {
		*error = g_error_new(decoder_quark(), DECODER_CODE_DONE, "done");
		return -1;
	}

	g_output_stream_write(output, outbuf, size, NULL, NULL);

	return size;
}

static void mpg123_decoder_close(struct decoder *decoder) {
	mpg123_handle *handle = decoder->data;
	mpg123_close(handle);
	mpg123_delete(handle);
}

static const gchar * const decoder_mpg123_extensions[] = {
	"mp3", NULL,
};

const struct decoder_plugin decoder_mpg123_decoder = {
	.name = "mpg123",
	.extensions = decoder_mpg123_extensions,
	.init = mpg123_decoder_init,
	.decode = mpg123_decoder_decode,
	.close = mpg123_decoder_close,
};