mp3.c 14.3 KB
Newer Older
B
bernard.xiong 已提交
1 2 3
#include <rtthread.h>
#include <dfs_posix.h>
#include <mp3/pub/mp3dec.h>
4
#include <string.h>
5

6 7
#include "board.h"
#include "netbuffer.h"
8 9
#include "player_ui.h"
#include "player_bg.h"
10

11
#define MP3_AUDIO_BUF_SZ    8192
12 13 14
#ifndef MIN
#define MIN(x, y)			((x) < (y)? (x) : (y))
#endif
15

16
rt_uint8_t mp3_fd_buffer[MP3_AUDIO_BUF_SZ];
17 18 19 20 21 22 23 24 25

struct mp3_decoder
{
    /* mp3 information */
    HMP3Decoder decoder;
    MP3FrameInfo frame_info;
    rt_uint32_t frames;

    /* mp3 file descriptor */
26 27
	rt_size_t (*fetch_data)(void* parameter, rt_uint8_t *buffer, rt_size_t length);
	void* fetch_parameter;
28 29

    /* mp3 read session */
30 31
    rt_uint8_t *read_buffer, *read_ptr;
    rt_int32_t  read_offset;
32 33 34 35 36 37 38
    rt_uint32_t bytes_left, bytes_left_before_decoding;

	/* audio device */
	rt_device_t snd_device;
};

static rt_err_t mp3_decoder_tx_done(rt_device_t dev, void *buffer)
B
bernard.xiong 已提交
39
{
40 41
	/* release memory block */
	sbuf_release(buffer);
42 43

	return RT_EOK;
B
bernard.xiong 已提交
44 45
}

46
void mp3_decoder_init(struct mp3_decoder* decoder)
B
bernard.xiong 已提交
47
{
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    RT_ASSERT(decoder != RT_NULL);

	/* init read session */
	decoder->read_ptr = RT_NULL;
	decoder->bytes_left_before_decoding = decoder->bytes_left = 0;
	decoder->frames = 0;

    // decoder->read_buffer = rt_malloc(MP3_AUDIO_BUF_SZ);
    decoder->read_buffer = &mp3_fd_buffer[0];
	if (decoder->read_buffer == RT_NULL) return;

    decoder->decoder = MP3InitDecoder();

	/* open audio device */
	decoder->snd_device = rt_device_find("snd");
	if (decoder->snd_device != RT_NULL)
	{
		/* set tx complete call back function */
		rt_device_set_tx_complete(decoder->snd_device, mp3_decoder_tx_done);
		rt_device_open(decoder->snd_device, RT_DEVICE_OFLAG_WRONLY);
	}
B
bernard.xiong 已提交
69 70
}

71
void mp3_decoder_detach(struct mp3_decoder* decoder)
B
bernard.xiong 已提交
72
{
73 74 75 76 77
    RT_ASSERT(decoder != RT_NULL);

	/* close audio device */
	if (decoder->snd_device != RT_NULL)
		rt_device_close(decoder->snd_device);
78

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
	/* release mp3 decoder */
    MP3FreeDecoder(decoder->decoder);
}

struct mp3_decoder* mp3_decoder_create()
{
    struct mp3_decoder* decoder;

	/* allocate object */
    decoder = (struct mp3_decoder*) rt_malloc (sizeof(struct mp3_decoder));
    if (decoder != RT_NULL)
    {
        mp3_decoder_init(decoder);
    }

    return decoder;
B
bernard.xiong 已提交
95 96
}

97
void mp3_decoder_delete(struct mp3_decoder* decoder)
B
bernard.xiong 已提交
98
{
99 100 101 102 103 104
    RT_ASSERT(decoder != RT_NULL);

	/* de-init mp3 decoder object */
	mp3_decoder_detach(decoder);
	/* release this object */
    rt_free(decoder);
B
bernard.xiong 已提交
105 106
}

107 108
rt_uint32_t current_offset = 0;
static rt_int32_t mp3_decoder_fill_buffer(struct mp3_decoder* decoder)
B
bernard.xiong 已提交
109
{
110 111 112 113 114 115
	rt_size_t bytes_read;
	rt_size_t bytes_to_read;

	// rt_kprintf("left: %d. refilling inbuffer...\n", decoder->bytes_left);
	if (decoder->bytes_left > 0)
	{
B
bernard.xiong 已提交
116
		// better: move unused rest of buffer to the start
117 118 119 120
		rt_memmove(decoder->read_buffer, decoder->read_ptr, decoder->bytes_left);
	}

	bytes_to_read = (MP3_AUDIO_BUF_SZ - decoder->bytes_left) & ~(512 - 1);
121 122 123

	bytes_read = decoder->fetch_data(decoder->fetch_parameter,
		(rt_uint8_t *)(decoder->read_buffer + decoder->bytes_left),
124 125
        bytes_to_read);

126
	if (bytes_read != 0)
B
bernard.xiong 已提交
127
	{
128 129
		decoder->read_ptr = decoder->read_buffer;
		decoder->read_offset = 0;
130
		decoder->bytes_left = decoder->bytes_left + bytes_read;
B
bernard.xiong 已提交
131 132 133 134
		return 0;
	}
	else
	{
135
		rt_kprintf("can't read more data\n");
B
bernard.xiong 已提交
136 137 138 139
		return -1;
	}
}

140
int mp3_decoder_run(struct mp3_decoder* decoder)
B
bernard.xiong 已提交
141
{
142 143
	int err;
	rt_uint16_t* buffer;
144
	rt_uint32_t  delta;
145 146 147

    RT_ASSERT(decoder != RT_NULL);

148 149
	if (player_is_playing() != RT_TRUE) return -1;

150
	if ((decoder->read_ptr == RT_NULL) || decoder->bytes_left < 2*MAINBUF_SIZE)
B
bernard.xiong 已提交
151
	{
152 153
		if(mp3_decoder_fill_buffer(decoder) != 0)
			return -1;
B
bernard.xiong 已提交
154 155
	}

156 157 158
	// rt_kprintf("read offset: 0x%08x\n", decoder->read_ptr - decoder->read_buffer);
	decoder->read_offset = MP3FindSyncWord(decoder->read_ptr, decoder->bytes_left);
	if (decoder->read_offset < 0)
B
bernard.xiong 已提交
159
	{
B
bernard.xiong 已提交
160 161
		/* discard this data */
		rt_kprintf("outof sync\n");
162

B
bernard.xiong 已提交
163 164
		decoder->bytes_left = 0;
		return 0;
B
bernard.xiong 已提交
165 166
	}

167
	decoder->read_ptr += decoder->read_offset;
168
	delta = decoder->read_offset;
169 170 171
	decoder->bytes_left -= decoder->read_offset;
	if (decoder->bytes_left < 1024)
	{
B
bernard.xiong 已提交
172
		/* fill more data */
173 174
		if(mp3_decoder_fill_buffer(decoder) != 0)
			return -1;
B
bernard.xiong 已提交
175 176
	}

177
    /* get a decoder buffer */
178
    buffer = (rt_uint16_t*)sbuf_alloc();
B
bernard.xiong 已提交
179
	decoder->bytes_left_before_decoding = decoder->bytes_left;
B
bernard.xiong 已提交
180

181 182
	err = MP3Decode(decoder->decoder, &decoder->read_ptr,
        (int*)&decoder->bytes_left, (short*)buffer, 0);
183 184 185 186
	delta += (decoder->bytes_left_before_decoding - decoder->bytes_left);

	current_offset += delta;
	player_set_position(current_offset);
B
bernard.xiong 已提交
187

188
	// rt_kprintf("bytes left after decode: %d\n", decoder->bytes_left);
189

190 191 192
	decoder->frames++;

	if (err != ERR_MP3_NONE)
B
bernard.xiong 已提交
193
	{
194
		switch (err)
B
bernard.xiong 已提交
195 196
		{
		case ERR_MP3_INDATA_UNDERFLOW:
197 198 199
			rt_kprintf("ERR_MP3_INDATA_UNDERFLOW\n");
			decoder->bytes_left = 0;
			if(mp3_decoder_fill_buffer(decoder) != 0)
B
bernard.xiong 已提交
200 201 202
			{
				/* release this memory block */
				sbuf_release(buffer);
203
				return -1;
B
bernard.xiong 已提交
204
			}
205 206 207 208 209
			break;

		case ERR_MP3_MAINDATA_UNDERFLOW:
			/* do nothing - next call to decode will provide more mainData */
			rt_kprintf("ERR_MP3_MAINDATA_UNDERFLOW\n");
B
bernard.xiong 已提交
210 211
			break;

212
		default:
B
bernard.xiong 已提交
213 214
			rt_kprintf("unknown error: %d, left: %d\n", err, decoder->bytes_left);

215 216
			// skip this frame
			if (decoder->bytes_left > 0)
B
bernard.xiong 已提交
217
			{
218 219 220
				decoder->bytes_left --;
				decoder->read_ptr ++;
			}
B
bernard.xiong 已提交
221 222
			else
			{
223 224 225 226 227
				// TODO
				RT_ASSERT(0);
			}
			break;
		}
B
bernard.xiong 已提交
228

229
		/* release this memory block */
230
		sbuf_release(buffer);
B
bernard.xiong 已提交
231 232 233 234
	}
	else
	{
		/* no error */
235
		MP3GetLastFrameInfo(decoder->decoder, &decoder->frame_info);
B
bernard.xiong 已提交
236

237 238 239
        /* set sample rate */

		/* write to sound device */
B
bernard.xiong 已提交
240 241 242 243 244 245 246 247 248
		if (decoder->frame_info.outputSamps > 0)
		{
			rt_device_write(decoder->snd_device, 0, buffer, decoder->frame_info.outputSamps * 2);
		}
		else
		{
			/* no output */
			sbuf_release(buffer);
		}
B
bernard.xiong 已提交
249 250 251 252 253
	}

	return 0;
}

254
static int mp3_parse_id3v1(int fd, struct tag_info *info)
255
{
256 257
	lseek(fd, -128, SEEK_END);
	read(fd, (char *) mp3_fd_buffer, 128);
258

259 260
	/* ID3v1 */
	if (strncmp("TAG", (char *) mp3_fd_buffer, 3) == 0)
261
	{
262 263 264
		strncpy(info->title, (char *) mp3_fd_buffer + 3, MIN(30, sizeof(info->title) - 1));
		strncpy(info->artist, (char *) mp3_fd_buffer + 3 + 30, MIN(30, sizeof(info->artist) - 1));
		return 0;
265
	}
266 267
	return -1;
}
B
bernard.xiong 已提交
268

269 270 271 272 273 274
static int mp3_parse_id3v2(int fd, struct tag_info *info)
{
	rt_uint32_t p = 0;

	lseek(fd, 0, SEEK_SET);
	read(fd, (char *) mp3_fd_buffer, sizeof(mp3_fd_buffer));
275

276
	if (strncmp("ID3", (char *) mp3_fd_buffer, 3) == 0)
277 278 279 280 281
	{
		rt_uint32_t tag_size, frame_size, i;
		rt_uint8_t version_major;
		int frame_header_size;

282
		tag_size = ((rt_uint32_t) mp3_fd_buffer[6] << 21) | ((rt_uint32_t) mp3_fd_buffer[7] << 14) | ((rt_uint16_t) mp3_fd_buffer[8] << 7) | mp3_fd_buffer[9];
283
		info->data_start = tag_size;
284
		version_major = mp3_fd_buffer[3];
285 286 287 288 289 290 291 292
		if (version_major >= 3)
		{
			frame_header_size = 10;
		}
		else
		{
			frame_header_size = 6;
		}
293
		i = p = 10;
294 295

		// iterate through frames
296
		while (p < tag_size)
297 298 299
		{
			if (version_major >= 3)
			{
300
				frame_size = ((rt_uint32_t) mp3_fd_buffer[i + 4] << 24) | ((rt_uint32_t) mp3_fd_buffer[i + 5] << 16) | ((rt_uint16_t) mp3_fd_buffer[i + 6] << 8) | mp3_fd_buffer[i + 7];
301 302 303
			}
			else
			{
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
				frame_size = ((rt_uint32_t) mp3_fd_buffer[i + 3] << 14) | ((rt_uint16_t) mp3_fd_buffer[i + 4] << 7) | mp3_fd_buffer[i + 5];
			}
			if (i + frame_size + frame_header_size + frame_header_size >= sizeof(mp3_fd_buffer))
			{
				if (frame_size + frame_header_size > sizeof(mp3_fd_buffer))
				{
					lseek(fd, p + frame_size + frame_header_size, SEEK_CUR);
					read(fd, (char *) mp3_fd_buffer, sizeof(mp3_fd_buffer));
					p += frame_size + frame_header_size;
					i = 0;
					continue;
				}
				else
				{
					int r = sizeof(mp3_fd_buffer) - i;
					memmove(mp3_fd_buffer, mp3_fd_buffer + i, r);
					read(fd, (char *) mp3_fd_buffer + r, i);
					i = 0;
				}
323 324
			}

325
			if (strncmp("TT2", (char *) mp3_fd_buffer + i, 3) == 0 || strncmp("TIT2", (char *) mp3_fd_buffer + i, 4) == 0)
326
			{
327
				strncpy(info->title, (char *) mp3_fd_buffer + i + frame_header_size + 1, MIN(frame_size - 1, sizeof(info->title) - 1));
328
			}
329
			else if (strncmp("TP1", (char *) mp3_fd_buffer + i, 3) == 0 || strncmp("TPE1", (char *) mp3_fd_buffer + i, 4) == 0)
330
			{
331
				strncpy(info->artist, (char *) mp3_fd_buffer + i + frame_header_size + 1, MIN(frame_size - 1, sizeof(info->artist) - 1));
332 333
			}

334
			p += frame_size + frame_header_size;
335 336
			i += frame_size + frame_header_size;
		}
337 338

		return 0;
339
	}
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

	return -1;
}

/* get mp3 information */
void mp3_get_info(const char* filename, struct tag_info* info)
{
	int fd;
	rt_size_t bytes_read;
	int sync_word;
    HMP3Decoder decoder;
    MP3FrameInfo frame_info;

	if (filename == RT_NULL || info == RT_NULL) return;

	fd = open(filename, O_RDONLY, 0);
	if (fd < 0) return; /* can't read file */

	/* init decoder */
	decoder = MP3InitDecoder();

	info->data_start = 0;

	/*
	 * TODO - Add UTF-8 support and fix this.
	 *
	 * ID3 v2 is generally useless here, because it
	 * uses UTF-8 encoding, which we can't handle right now.
	 * But parsing v2 first is nesessary in order to
	 * find the correct MP3 frame header location,
	 * in case of the ID3 v2 tag should be there.
	 */
//	if (mp3_parse_id3v2(fd, info) < 0)
//	{
//		// ID3 v2 is not available. Fall back to ID3 v1.
//		mp3_parse_id3v1(fd, info);
//	}
	mp3_parse_id3v2(fd, info);
	mp3_parse_id3v1(fd, info);

	lseek(fd, info->data_start, SEEK_SET);
	bytes_read = read(fd, (char *) mp3_fd_buffer, sizeof(mp3_fd_buffer));

	/* get frame information */
	sync_word = MP3FindSyncWord(mp3_fd_buffer, bytes_read);
	if (sync_word >= 0)
386
	{
387 388 389 390 391
		rt_uint32_t p;
		short samples_per_frame;

		/* get frame information */
		MP3GetNextFrameInfo(decoder, &frame_info, &mp3_fd_buffer[sync_word]);
392

393 394 395 396 397 398 399
		// Try to locate the Xing VBR header.
		if (frame_info.version == MPEG1)
		{
			p = frame_info.nChans == 2 ? 32 : 17;
			samples_per_frame = 1152;
		}
		else
400
		{
401 402
			p = frame_info.nChans == 2 ? 17 : 9;
			samples_per_frame = 576;
403
		}
404
		p += sync_word + 4;
405

406 407 408 409 410 411 412 413 414 415 416
		if (strncmp("Xing", (char *) mp3_fd_buffer + p, 4) || strncmp("Info", (char *) mp3_fd_buffer + p, 4))
		{
			// VBR
			if (mp3_fd_buffer[p + 7] & 1 == 1) /* Checks if the frames field exists */
			{
				rt_uint32_t frames = ((rt_uint32_t) mp3_fd_buffer[p + 8] << 24) | ((rt_uint32_t) mp3_fd_buffer[p + 9] << 16) | ((rt_uint32_t) mp3_fd_buffer[p + 10] << 8) | (rt_uint32_t) mp3_fd_buffer[p + 11];
				info->duration = frames * samples_per_frame / frame_info.samprate;
			}
		}
		/*
		 * There're two other rarely used VBR header standards: VBRI & MLLT.
417
		 * I can't find any sample with these headers. So I just ignored them. :)
418 419 420 421 422 423 424 425
		 */
		else
		{
			// CBR
			info->duration = lseek(fd, 0, SEEK_END) / (frame_info.bitrate / 8); /* second */
		}
		info->bit_rate = frame_info.bitrate;
		info->sampling = frame_info.samprate;
426 427 428 429 430 431 432 433 434 435
	}

    /* set current position */
    info->position = 0;

	/* release mp3 decoder */
    MP3FreeDecoder(decoder);

	/* close file */
	close(fd);
436 437
}

B
bernard.xiong 已提交
438
#include <finsh.h>
439 440 441 442 443
rt_size_t fd_fetch(void* parameter, rt_uint8_t *buffer, rt_size_t length)
{
	int fd = (int)parameter;
	return read(fd, (char*)buffer, length);
}
B
bernard.xiong 已提交
444 445 446
void mp3(char* filename)
{
	int fd;
447
	struct mp3_decoder* decoder;
448 449 450
	extern rt_bool_t is_playing;
	
	is_playing = RT_TRUE;
B
bernard.xiong 已提交
451 452 453
	fd = open(filename, O_RDONLY, 0);
	if (fd >= 0)
	{
454 455 456
		decoder = mp3_decoder_create();
		if (decoder != RT_NULL)
		{
457 458 459
			decoder->fetch_data = fd_fetch;
			decoder->fetch_parameter = (void*)fd;

460
			current_offset = 0;
461
			while (mp3_decoder_run(decoder) != -1);
462

463 464 465
			/* delete decoder object */
			mp3_decoder_delete(decoder);
		}
466
		close(fd);
B
bernard.xiong 已提交
467
	}
468
	is_playing = RT_FALSE;
B
bernard.xiong 已提交
469
}
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
FINSH_FUNCTION_EXPORT(mp3, mp3 decode test);

#if STM32_EXT_SRAM
/* http mp3 */
#include "http.h"
static rt_size_t http_fetch(rt_uint8_t* ptr, rt_size_t len, void* parameter)
{
	struct http_session* session = (struct http_session*)parameter;
	RT_ASSERT(session != RT_NULL);

	return http_session_read(session, ptr, len);
}

static void http_close(void* parameter)
{
	struct http_session* session = (struct http_session*)parameter;
	RT_ASSERT(session != RT_NULL);

	http_session_close(session);
}

rt_size_t http_data_fetch(void* parameter, rt_uint8_t *buffer, rt_size_t length)
{
	return net_buf_read(buffer, length);
}
void http_mp3(char* url)
{
    struct http_session* session;
	struct mp3_decoder* decoder;
B
bernard.xiong 已提交
499 500 501
	extern rt_bool_t is_playing;
	
	is_playing = RT_TRUE;
502 503 504 505 506 507 508 509 510 511 512 513 514

	session = http_session_open(url);
	if (session != RT_NULL)
	{
		/* add a job to netbuf worker */
		net_buf_add_job(http_fetch, http_close, (void*)session);

		decoder = mp3_decoder_create();
		if (decoder != RT_NULL)
		{
			decoder->fetch_data = http_data_fetch;
			decoder->fetch_parameter = RT_NULL;

515
			current_offset = 0;
516 517 518 519 520 521 522 523 524
			while (mp3_decoder_run(decoder) != -1);

			/* delete decoder object */
			mp3_decoder_delete(decoder);
		}
		session = RT_NULL;
	}
}
FINSH_FUNCTION_EXPORT(http_mp3, http mp3 decode test);
B
bernard.xiong 已提交
525

526
/* ice mp3 */
B
bernard.xiong 已提交
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
static rt_size_t ice_fetch(rt_uint8_t* ptr, rt_size_t len, void* parameter)
{
	struct shoutcast_session* session = (struct shoutcast_session*)parameter;
	RT_ASSERT(session != RT_NULL);

	return shoutcast_session_read(session, ptr, len);
}

static void ice_close(void* parameter)
{
	struct shoutcast_session* session = (struct shoutcast_session*)parameter;
	RT_ASSERT(session != RT_NULL);

	shoutcast_session_close(session);
}

rt_size_t ice_data_fetch(void* parameter, rt_uint8_t *buffer, rt_size_t length)
{
	return net_buf_read(buffer, length);
}

void ice_mp3(char* url)
{
    struct shoutcast_session* session;
	struct mp3_decoder* decoder;
	extern rt_bool_t is_playing;

	is_playing = RT_TRUE;

	session = shoutcast_session_open(url);
	if (session != RT_NULL)
	{
		/* add a job to netbuf worker */
		net_buf_add_job(ice_fetch, ice_close, (void*)session);

		decoder = mp3_decoder_create();
		if (decoder != RT_NULL)
		{
			decoder->fetch_data = ice_data_fetch;
			decoder->fetch_parameter = RT_NULL;

			current_offset = 0;
			while (mp3_decoder_run(decoder) != -1);

			/* delete decoder object */
			mp3_decoder_delete(decoder);
		}
		session = RT_NULL;
	}
}
FINSH_FUNCTION_EXPORT(ice_mp3, shoutcast mp3 decode test);

579
#endif