run_decoder.cxx 5.07 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#include "config.h"
21
#include "IOThread.hxx"
22
#include "DecoderList.hxx"
23
#include "DecoderAPI.hxx"
24
#include "InputInit.hxx"
25
#include "InputStream.hxx"
26
#include "AudioFormat.hxx"
27
#include "util/Error.hxx"
28
#include "thread/Cond.hxx"
29
#include "Log.hxx"
30
#include "stdbin.h"
31

32
#ifdef HAVE_GLIB
33
#include <glib.h>
34
#endif
35 36 37

#include <assert.h>
#include <unistd.h>
38
#include <stdlib.h>
39
#include <stdio.h>
40

41
struct Decoder {
42 43
	const char *uri;

44
	const struct DecoderPlugin *plugin;
45 46 47 48 49

	bool initialized;
};

void
50
decoder_initialized(Decoder &decoder,
51
		    const AudioFormat audio_format,
52
		    gcc_unused bool seekable,
53
		    float duration)
54
{
55 56
	struct audio_format_string af_string;

57
	assert(!decoder.initialized);
58
	assert(audio_format.IsValid());
59

60 61 62
	fprintf(stderr, "audio_format=%s duration=%f\n",
		audio_format_to_string(audio_format, &af_string),
		duration);
63

64
	decoder.initialized = true;
65 66
}

67
DecoderCommand
68
decoder_get_command(gcc_unused Decoder &decoder)
69
{
70
	return DecoderCommand::NONE;
71 72
}

73 74
void
decoder_command_finished(gcc_unused Decoder &decoder)
75 76 77
{
}

78 79
double
decoder_seek_where(gcc_unused Decoder &decoder)
80 81 82 83
{
	return 1.0;
}

84 85
void
decoder_seek_error(gcc_unused Decoder &decoder)
86 87 88 89
{
}

size_t
90
decoder_read(gcc_unused Decoder *decoder,
91
	     InputStream &is,
92 93
	     void *buffer, size_t length)
{
94
	return is.LockRead(buffer, length, IgnoreError());
95 96
}

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
bool
decoder_read_full(Decoder *decoder, InputStream &is,
		  void *_buffer, size_t size)
{
	uint8_t *buffer = (uint8_t *)_buffer;

	while (size > 0) {
		size_t nbytes = decoder_read(decoder, is, buffer, size);
		if (nbytes == 0)
			return false;

		buffer += nbytes;
		size -= nbytes;
	}

	return true;
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
bool
decoder_skip(Decoder *decoder, InputStream &is, size_t size)
{
	while (size > 0) {
		char buffer[1024];
		size_t nbytes = decoder_read(decoder, is, buffer,
					     std::min(sizeof(buffer), size));
		if (nbytes == 0)
			return false;

		size -= nbytes;
	}

	return true;
}

131
void
132
decoder_timestamp(gcc_unused Decoder &decoder,
133
		  gcc_unused double t)
134 135 136
{
}

137
DecoderCommand
138
decoder_data(gcc_unused Decoder &decoder,
139
	     gcc_unused InputStream *is,
140
	     const void *data, size_t datalen,
141
	     gcc_unused uint16_t kbit_rate)
142
{
143
	gcc_unused ssize_t nbytes = write(1, data, datalen);
144
	return DecoderCommand::NONE;
145 146
}

147
DecoderCommand
148
decoder_tag(gcc_unused Decoder &decoder,
149
	    gcc_unused InputStream *is,
150
	    gcc_unused Tag &&tag)
151
{
152
	return DecoderCommand::NONE;
153 154
}

155
void
156
decoder_replay_gain(gcc_unused Decoder &decoder,
157
		    const ReplayGainInfo *rgi)
158
{
159
	const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM];
160
	if (tuple->IsDefined())
161 162
		fprintf(stderr, "replay_gain[album]: gain=%f peak=%f\n",
			tuple->gain, tuple->peak);
163

164
	tuple = &rgi->tuples[REPLAY_GAIN_TRACK];
165
	if (tuple->IsDefined())
166 167
		fprintf(stderr, "replay_gain[track]: gain=%f peak=%f\n",
			tuple->gain, tuple->peak);
168 169
}

170
void
171
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
172 173 174
{
}

175 176 177 178 179
int main(int argc, char **argv)
{
	const char *decoder_name;

	if (argc != 3) {
180 181
		fprintf(stderr, "Usage: run_decoder DECODER URI >OUT\n");
		return EXIT_FAILURE;
182 183
	}

184
	Decoder decoder;
185 186 187
	decoder_name = argv[1];
	decoder.uri = argv[2];

188
#ifdef HAVE_GLIB
189
#if !GLIB_CHECK_VERSION(2,32,0)
190
	g_thread_init(NULL);
191
#endif
192 193
#endif

194
	io_thread_init();
195
	io_thread_start();
196

197 198
	Error error;
	if (!input_stream_global_init(error)) {
199
		LogError(error);
200
		return EXIT_FAILURE;
201 202
	}

203 204 205 206
	decoder_plugin_init_all();

	decoder.plugin = decoder_plugin_from_name(decoder_name);
	if (decoder.plugin == NULL) {
207 208
		fprintf(stderr, "No such decoder: %s\n", decoder_name);
		return EXIT_FAILURE;
209 210
	}

211 212
	decoder.initialized = false;

213
	if (decoder.plugin->file_decode != NULL) {
214
		decoder.plugin->FileDecode(decoder, decoder.uri);
215
	} else if (decoder.plugin->stream_decode != NULL) {
216 217
		Mutex mutex;
		Cond cond;
218

219 220
		InputStream *is =
			InputStream::Open(decoder.uri, mutex, cond, error);
221
		if (is == NULL) {
222
			if (error.IsDefined())
223
				LogError(error);
224
			else
225
				fprintf(stderr, "InputStream::Open() failed\n");
226

227
			return EXIT_FAILURE;
228
		}
229

230
		decoder.plugin->StreamDecode(decoder, *is);
231

232
		is->Close();
233
	} else {
234 235
		fprintf(stderr, "Decoder plugin is not usable\n");
		return EXIT_FAILURE;
236 237 238
	}

	decoder_plugin_deinit_all();
239
	input_stream_global_finish();
240
	io_thread_deinit();
241 242

	if (!decoder.initialized) {
243 244
		fprintf(stderr, "Decoding failed\n");
		return EXIT_FAILURE;
245 246 247 248
	}

	return 0;
}