2009-08-26 Chris Toshok <toshok@ximian.com>
[moon.git] / src / mp3.cpp
blob8a4b5ecc380f45a7916f78d1f3888fa1472ba125
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * mp3.cpp: Pipeline for the media
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
15 #include <config.h>
17 #include "mp3.h"
18 #include "pipeline.h"
19 #include "clock.h"
20 #include "debug.h"
23 // Relevant links to documentation:
24 // http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx
25 // http://www.mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
26 // http://www.compuphase.com/mp3/sta013.htm
30 * MPEG Audio Demuxer
33 static int mpeg1_bitrates[3][15] = {
34 /* version 1, layer 1 */
35 { 0, 32000, 48000, 56000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000 },
36 /* version 1, layer 2 */
37 { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000 },
38 /* version 1, layer 3 */
39 { 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000 },
42 static int mpeg2_bitrates[3][15] = {
43 /* version 2, layer 1 */
44 { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000 },
45 /* version 2, layer 2 */
46 { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000 },
47 /* version 2, layer 3 */
48 { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000 }
51 static bool
52 mpeg_parse_bitrate (MpegFrameHeader *mpeg, guint8 byte)
54 int i = (byte & 0xf0) >> 4;
56 if (i > 14)
57 return false;
59 if (mpeg->version == 1)
60 mpeg->bit_rate = mpeg1_bitrates[mpeg->layer - 1][i];
61 else
62 mpeg->bit_rate = mpeg2_bitrates[mpeg->layer - 1][i];
64 return true;
67 static guint8
68 mpeg_encode_bitrate (MpegFrameHeader *mpeg, int bit_rate)
70 int i;
72 if (mpeg->version == 1) {
73 for (i = 1; i < 15; i++) {
74 if (mpeg1_bitrates[mpeg->layer - 1][i] == bit_rate)
75 break;
77 } else {
78 for (i = 1; i < 15; i++) {
79 if (mpeg2_bitrates[mpeg->layer - 1][i] == bit_rate)
80 break;
84 if (i == 15)
85 return 0;
87 return ((i << 4) & 0xf0);
90 static int mpeg_samplerates[3][3] = {
91 { 44100, 48000, 32000 }, // version 1
92 { 22050, 24000, 16000 }, // version 2
93 { 11025, 12000, 8000 } // version 2.5
96 static bool
97 mpeg_parse_samplerate (MpegFrameHeader *mpeg, guint8 byte)
99 int i = (byte >> 2) & 0x03;
101 if (i > 2)
102 return false;
104 mpeg->sample_rate = mpeg_samplerates[mpeg->version - 1][i];
106 return true;
109 static bool
110 mpeg_parse_channels (MpegFrameHeader *mpeg, guint8 byte)
112 int mode = (byte >> 6) & 0x03;
114 switch (mode) {
115 case 0: /* stereo */
116 mpeg->channels = 2;
117 break;
118 case 1: /* joint stereo */
119 mpeg->channels = 2;
120 break;
121 case 2: /* dual channel (2 mono channels) */
122 mpeg->channels = 2;
123 break;
124 case 3: /* mono */
125 mpeg->channels = 1;
126 break;
129 mpeg->intensity = (byte & 0x20) ? 1 : 0;
130 mpeg->ms = (byte & 0x10) ? 1 : 0;
132 return true;
135 bool
136 mpeg_parse_header (MpegFrameHeader *mpeg, const guint8 *buffer)
138 if (!is_mpeg_header (buffer))
139 return false;
141 // extract the MPEG version
142 switch ((buffer[1] >> 3) & 0x03) {
143 case 0: /* MPEG Version 2.5 */
144 mpeg->version = 3;
145 break;
146 case 1: /* reserved */
147 return false;
148 case 2: /* MPEG Version 2 */
149 mpeg->version = 2;
150 break;
151 case 3: /* MPEG Version 1 */
152 mpeg->version = 1;
153 break;
156 // extract the MPEG layer
157 switch ((buffer[1] >> 1) & 0x03) {
158 case 1:
159 mpeg->layer = 3;
160 break;
161 case 2:
162 mpeg->layer = 1;
163 break;
164 case 3:
165 mpeg->layer = 2;
166 break;
167 default:
168 // invalid layer
169 return false;
172 // protection (via 16bit crc) bit
173 mpeg->prot = (buffer[1] & 0x01) ? 1 : 0;
175 // extract the bit rate
176 if (!mpeg_parse_bitrate (mpeg, buffer[2]))
177 return false;
179 // extract the sample rate
180 if (!mpeg_parse_samplerate (mpeg, buffer[2]))
181 return false;
183 // check if the frame is padded
184 mpeg->padded = (buffer[2] & 0x02) ? 1 : 0;
186 // extract the channel mode */
187 if (!mpeg_parse_channels (mpeg, buffer[3]))
188 return false;
190 mpeg->copyright = (buffer[3] & 0x08) ? 1 : 0;
191 mpeg->original = (buffer[3] & 0x04) ? 1 : 0;
193 return true;
196 static int mpeg_block_sizes[3][3] = {
197 { 384, 1152, 1152 }, // version 1
198 { 384, 1152, 576 }, // version 2
199 { 384, 1152, 576 } // version 2.5
202 #define mpeg_block_size(mpeg) mpeg_block_sizes[(mpeg)->version - 1][(mpeg)->layer - 1]
204 double
205 mpeg_frame_length (MpegFrameHeader *mpeg, bool xing)
207 double len;
209 // calculate the frame length
210 if (mpeg->layer == 1)
211 len = (((12 * mpeg->bit_rate) / (double) mpeg->sample_rate) + mpeg->padded) * 4;
212 else if (mpeg->version == 1)
213 len = ((144 * mpeg->bit_rate) / (double) mpeg->sample_rate) + mpeg->padded;
214 else
215 len = ((72 * mpeg->bit_rate) / (double) mpeg->sample_rate) + mpeg->padded;
217 return len;
220 #define MPEG_FRAME_LENGTH_MAX ((((144 * 160000) / 8000) + 1) + 2)
222 #define mpeg_frame_size(mpeg) (((mpeg)->bit_rate * (mpeg)->channels * mpeg_block_size (mpeg)) / (mpeg)->sample_rate)
224 static guint64
225 mpeg_frame_duration (MpegFrameHeader *mpeg)
227 guint64 result = ((guint64) mpeg_block_size (mpeg)) * TIMESPANTICKS_IN_SECOND / mpeg->sample_rate;
228 return result;
231 #if 0
232 static void
233 mpeg_print_info (MpegFrameHeader *mpeg)
235 const char *version;
237 switch (mpeg->version) {
238 case 1:
239 version = "1";
240 break;
241 case 2:
242 version = "2";
243 break;
244 default:
245 version = "2.5";
246 break;
249 printf ("MPEG-%s Audio Layer %d; %d Hz, %d ch, %d kbit\n",
250 version, mpeg->layer, mpeg->sample_rate, mpeg->channels,
251 mpeg->bit_rate / 1000);
253 printf ("\t16bit crc=%s; padded=%s\n", mpeg->prot ? "true" : "false",
254 mpeg->padded ? "true" : "false");
256 printf ("\tframe length = %u bytes\n", mpeg_frame_length (mpeg, false));
258 #endif
260 static int
261 mpeg_xing_header_offset (MpegFrameHeader *mpeg)
263 if (mpeg->version == 1)
264 return mpeg->channels == 1 ? 21 : 36;
265 else
266 return mpeg->channels == 1 ? 13 : 21;
269 #define mpeg_vbri_header_offset 36
271 static bool
272 mpeg_check_vbr_headers (MpegFrameHeader *mpeg, MpegVBRHeader *vbr, IMediaSource *source, gint64 pos)
274 guint32 nframes = 0, size = 0;
275 double len;
276 guint8 buffer[24], *bufptr;
277 gint64 offset;
278 int i;
280 // first, check for a Xing header
281 offset = mpeg_xing_header_offset (mpeg);
282 if (!source->Seek (pos + offset, SEEK_SET))
283 return false;
285 if (!source->Peek (buffer, 16))
286 return false;
288 if (!strncmp ((const char *) buffer, "Xing", 4)) {
289 if (buffer [7] & 0x01) {
290 // decode the number of frames
291 nframes = (buffer [8] << 24) + (buffer [9] << 16) + (buffer [10] << 8) + buffer [11];
292 } else if (buffer [7] & 0x02) {
293 size = (buffer [8] << 24) + (buffer [9] << 16) + (buffer [10] << 8) + buffer [11];
295 // calculate the frame length
296 len = mpeg_frame_length (mpeg, true);
298 // estimate the number of frames
299 nframes = size / len;
302 vbr->type = MpegXingHeader;
303 vbr->nframes = nframes;
305 return true;
308 // check for a Fraunhofer VBRI header
309 offset = mpeg_vbri_header_offset;
310 if (!source->Seek (pos + offset, SEEK_SET))
311 return false;
313 if (!source->Peek (buffer, 24))
314 return false;
316 if (!strncmp ((const char *) buffer, "VBRI", 4)) {
317 // decode the number of frames
318 bufptr = buffer + 14;
319 for (i = 0; i < 4; i++)
320 nframes = (nframes << 8) | *bufptr++;
322 vbr->type = MpegVBRIHeader;
323 vbr->nframes = nframes;
325 return true;
328 return false;
332 #define MPEG_JUMP_TABLE_GROW_SIZE 16
334 Mp3FrameReader::Mp3FrameReader (IMediaSource *source, AudioStream *stream, gint64 start, guint32 frame_len, guint32 frame_duration, bool xing)
336 jmptab = g_new (MpegFrame, MPEG_JUMP_TABLE_GROW_SIZE);
337 avail = MPEG_JUMP_TABLE_GROW_SIZE;
338 used = 0;
340 this->frame_dur = frame_duration;
341 this->frame_len = frame_len;
342 this->xing = xing;
343 this->sync_lost = false;
345 stream_start = start;
346 this->source = source;
347 this->stream = stream;
349 bit_rate = 0;
350 cur_pts = 0;
353 Mp3FrameReader::~Mp3FrameReader ()
355 g_free (jmptab);
358 void
359 Mp3FrameReader::AddFrameIndex (gint64 offset, guint64 pts, guint32 dur, gint32 bit_rate)
361 if (used == avail) {
362 avail += MPEG_JUMP_TABLE_GROW_SIZE;
363 jmptab = (MpegFrame *) g_realloc (jmptab, avail * sizeof (MpegFrame));
366 jmptab[used].bit_rate = bit_rate;
367 jmptab[used].offset = offset;
368 jmptab[used].pts = pts;
369 jmptab[used].dur = dur;
371 used++;
375 * MID:
376 * @lo: the low bound
377 * @hi: the high bound
379 * Finds the midpoint between positive integer values, @lo and @hi.
381 * Notes: Typically expressed as '(@lo + @hi) / 2', this is incorrect
382 * when @lo and @hi are sufficiently large enough that combining them
383 * would overflow their integer type. To work around this, we use the
384 * formula, '@lo + ((@hi - @lo) / 2)', thus preventing this problem
385 * from occuring.
387 * Returns the midpoint between @lo and @hi (rounded down).
389 #define MID(lo, hi) (lo + ((hi - lo) >> 1))
391 guint32
392 Mp3FrameReader::MpegFrameSearch (guint64 pts)
394 guint64 start, end;
395 guint32 hi = used - 1;
396 guint32 m = hi >> 1;
397 guint32 lo = 0;
399 do {
400 end = start = jmptab[m].pts;
401 end += jmptab[m].dur;
403 if (pts > end) {
404 lo = m + 1;
405 } else if (pts < start) {
406 hi = m;
407 } else {
408 if (pts == end) {
409 // pts should be exactly the beginning of the next frame
410 m++;
413 break;
416 m = MID (lo, hi);
417 } while (lo < hi);
419 return m;
422 MediaResult
423 Mp3FrameReader::Seek (guint64 pts)
425 gint64 offset = source->GetPosition ();
426 gint32 bit_rate = this->bit_rate;
427 guint64 cur_pts = this->cur_pts;
428 guint32 frame;
429 MediaResult result = MEDIA_FAIL;
431 if (pts == cur_pts)
432 return MEDIA_SUCCESS;
434 if (pts == 0) {
435 if (!source->Seek (stream_start, SEEK_SET)) {
436 LOG_MP3 ("Mp3FrameReader::Seek (%" G_GUINT64_FORMAT "): Seek error (#1)\n", pts);
437 goto exception;
440 bit_rate = 0;
441 cur_pts = 0;
443 return MEDIA_SUCCESS;
446 // if we are seeking to some place we've been, then we can use our jump table
447 if (used > 0 && pts < (jmptab[used - 1].pts + jmptab[used - 1].dur)) {
448 if (pts >= jmptab[used - 1].pts) {
449 if (!source->Seek (jmptab[used - 1].offset, SEEK_SET)) {
450 LOG_MP3 ("Mp3FrameReader::Seek (%" G_GUINT64_FORMAT "): Seek error (#2)\n", pts)
451 goto exception;
454 this->bit_rate = jmptab[used - 1].bit_rate;
455 this->cur_pts = jmptab[used - 1].pts;
457 return MEDIA_SUCCESS;
460 // search for our requested pts
461 frame = MpegFrameSearch (pts);
463 if (!source->Seek (jmptab[frame].offset, SEEK_SET)) {
464 LOG_MP3 ("Mp3FrameReader::Seek (%" G_GUINT64_FORMAT "): Seek error (#3)\n", pts);
465 goto exception;
468 this->bit_rate = jmptab[frame].bit_rate;
469 this->cur_pts = jmptab[frame].pts;
471 return MEDIA_SUCCESS;
474 // keep skipping frames until we read to (or past) the requested pts
475 while (this->cur_pts < pts) {
476 result = SkipFrame ();
478 if (!MEDIA_SUCCEEDED (result)) {
479 LOG_MP3 ("Mp3FrameReader::Seek (%" G_GUINT64_FORMAT "): Error while skipping frame: %i\n", pts, result);
480 goto exception;
484 // pts requested is at the start of the next frame in the source
485 if (this->cur_pts == pts)
486 return MEDIA_SUCCESS;
488 // pts requested was non-key frame, need to seek back to the most recent key frame
489 if (!source->Seek (jmptab[used - 1].offset, SEEK_SET)) {
490 LOG_MP3 ("Mp3FrameReader::Seek (%" G_GUINT64_FORMAT "): Seek error (#4)\n", pts);
491 goto exception;
494 this->bit_rate = jmptab[used - 1].bit_rate;
495 this->cur_pts = jmptab[used - 1].pts;
497 return MEDIA_SUCCESS;
499 exception:
501 // restore FrameReader to previous state
502 source->Seek (offset, SEEK_SET);
503 this->bit_rate = bit_rate;
504 this->cur_pts = cur_pts;
506 LOG_MP3 ("Mp3FrameReader::Seek (%" G_GUINT64_FORMAT "): Could not find pts\n", pts);
508 return result;
511 MediaResult
512 Mp3FrameReader::SkipFrame ()
514 MpegFrameHeader mpeg;
515 guint64 duration;
516 guint8 buffer[4];
517 gint64 offset;
518 guint32 len;
519 bool eof;
521 offset = source->GetPosition ();
523 if (!source->IsPositionAvailable (offset + 4, &eof))
524 return eof ? MEDIA_FAIL : MEDIA_NOT_ENOUGH_DATA;
526 if (!source->Peek (buffer, 4))
527 return MEDIA_FAIL;
529 if (!mpeg_parse_header (&mpeg, buffer)) {
530 sync_lost = true;
531 return MEDIA_FAIL;
534 if (mpeg.bit_rate == 0) {
535 // use the most recently specified bit rate
536 mpeg.bit_rate = bit_rate;
539 bit_rate = mpeg.bit_rate;
541 duration = mpeg_frame_duration (&mpeg);
543 if (used == 0 || offset > jmptab[used - 1].offset)
544 AddFrameIndex (offset, cur_pts, duration, bit_rate);
546 len = (guint32) mpeg_frame_length (&mpeg, xing);
548 if (!source->IsPositionAvailable (offset + len, &eof))
549 return eof ? MEDIA_FAIL : MEDIA_NOT_ENOUGH_DATA;
551 if (!source->Seek ((gint64) len, SEEK_CUR))
552 return MEDIA_FAIL;
554 cur_pts += duration;
556 stream->SetLastAvailablePts (cur_pts);
558 return MEDIA_SUCCESS;
561 MediaResult
562 Mp3FrameReader::TryReadFrame (MediaFrame **f)
564 MpegFrameHeader mpeg;
565 guint64 duration;
566 guint8 buffer[4];
567 gint64 offset;
568 guint32 len;
569 MediaFrame *frame;
570 bool eof = false;
571 MediaResult result;
574 if (sync_lost) {
575 result = FindMpegHeader (&mpeg, NULL, source, source->GetPosition (), &offset);
576 if (!MEDIA_SUCCEEDED (result))
577 return result;
579 if (!source->IsPositionAvailable (offset, &eof))
580 return eof ? MEDIA_NO_MORE_DATA : MEDIA_NOT_ENOUGH_DATA;
582 if (!source->Seek (offset, SEEK_SET))
583 return MEDIA_FAIL;
584 sync_lost = false;
585 } else {
586 offset = source->GetPosition ();
589 // Check if there is enough data available
590 if (!source->IsPositionAvailable (offset + 4, &eof)) {
591 //printf ("Mp3FrameReader::TryReadFrame (): Exit 2: Buffer underflow (last available pos: %lld, offset: %" G_GUINT64_FORMAT ", diff: %" G_GUINT64_FORMAT ", len: %u)\n", source->GetLastAvailablePosition (), offset, source->GetLastAvailablePosition () - offset, len);
592 return eof? MEDIA_NO_MORE_DATA : MEDIA_NOT_ENOUGH_DATA;
595 if (!source->Peek (buffer, 4)) {
596 //printf ("Mp3FrameReader::TryReadFrame (): Exit 3\n");
597 return MEDIA_FAIL; // Now this shouldn't fail, given that we've checked for the previous error conditions
600 if (!mpeg_parse_header (&mpeg, buffer)) {
601 //printf ("Mp3FrameReader::TryReadFrame (): Exit 4\n");
602 sync_lost = true;
603 return MEDIA_DEMUXER_ERROR;
606 //printf ("Mp3FrameReader::ReadFrame():\n");
607 //mpeg_print_info (&mpeg);
609 if (mpeg.bit_rate == 0) {
610 // use the most recently specified bit rate
611 mpeg.bit_rate = bit_rate;
613 // re-encode the bitrate into the header
614 buffer[2] |= mpeg_encode_bitrate (&mpeg, bit_rate);
617 bit_rate = mpeg.bit_rate;
619 duration = mpeg_frame_duration (&mpeg);
621 if (used == 0 || offset > jmptab[used - 1].offset)
622 AddFrameIndex (offset, cur_pts, duration, bit_rate);
624 len = (guint32) mpeg_frame_length (&mpeg, xing);
626 if (!source->IsPositionAvailable (offset + len, &eof)) {
627 //printf ("Mp3FrameReader::TryReadFrame (): Exit 6: Buffer underflow (last available pos: %lld, offset: %" G_GUINT64_FORMAT ", diff: %" G_GUINT64_FORMAT ", len: %u)\n", source->GetLastAvailablePosition (), offset, source->GetLastAvailablePosition () - offset, len);
628 return eof ? MEDIA_NO_MORE_DATA : MEDIA_BUFFER_UNDERFLOW;
631 frame = new MediaFrame (stream);
632 *f = frame;
633 frame->buflen = len;
635 if (mpeg.layer != 1 && !mpeg.padded)
636 frame->buffer = (guint8 *) g_try_malloc (frame->buflen + 1);
637 else
638 frame->buffer = (guint8 *) g_try_malloc (frame->buflen);
640 if (frame->buffer == NULL)
641 return MEDIA_OUT_OF_MEMORY;
643 if (mpeg.layer != 1 && !mpeg.padded)
644 frame->buffer[frame->buflen - 1] = 0;
646 if (!source->ReadAll (frame->buffer, len)) {
647 //printf ("Mp3FrameReader::TryReadFrame (): Exit 7\n");
648 return MEDIA_FAIL;
651 memcpy (frame->buffer, buffer, 4);
653 frame->pts = cur_pts;
654 frame->duration = duration;
656 frame->AddState (MediaFrameDemuxed);
658 cur_pts += duration;
660 return MEDIA_SUCCESS;
665 * Mp3Demuxer
668 Mp3Demuxer::Mp3Demuxer (Media *media, IMediaSource *source) : IMediaDemuxer (Type::MP3DEMUXER, media, source)
670 reader = NULL;
671 xing = false;
674 Mp3Demuxer::~Mp3Demuxer ()
676 if (reader)
677 delete reader;
680 void
681 Mp3Demuxer::SeekAsyncInternal (guint64 pts)
683 MediaResult result = MEDIA_FAIL;
685 if (reader)
686 result = reader->Seek (pts);
688 if (MEDIA_SUCCEEDED (result)) {
689 ReportSeekCompleted (pts);
690 } else if (result == MEDIA_NOT_ENOUGH_DATA) {
691 EnqueueSeek (pts);
692 } else {
693 ReportErrorOccurred (result);
697 MediaResult
698 Mp3FrameReader::FindMpegHeader (MpegFrameHeader *mpeg, MpegVBRHeader *vbr, IMediaSource *source, gint64 start, gint64 *result)
700 guint8 buf[4096], hdr[4], *inbuf, *inend;
701 gint64 pos, offset = start;
702 register guint8 *inptr;
703 MpegFrameHeader next;
704 gint32 n = 0;
705 guint32 len;
706 bool eof = false;
708 *result = -1;
710 if (!source->Seek (start, SEEK_SET))
711 return MEDIA_FAIL;
713 inbuf = buf;
715 do {
716 if (!source->IsPositionAvailable (offset + sizeof (buf) - n, &eof)) {
717 if (!eof) {
718 return MEDIA_NOT_ENOUGH_DATA;
720 // If we reached eof we still need to check if this is a valid mpeg header, so don't fail that case
723 if ((n = source->ReadSome (inbuf, sizeof (buf) - n)) <= 0)
724 return MEDIA_NO_MORE_DATA;
726 inend = inbuf + n;
727 inptr = buf;
729 if ((inend - inptr) < 4)
730 return MEDIA_FAIL;
732 do {
733 /* mpeg audio sync header begins with a 0xff */
734 while (inptr < inend && *inptr != 0xff) {
735 offset++;
736 inptr++;
739 if (inptr == inend)
740 break;
742 /* found a 0xff byte... could be a frame header */
743 if ((inptr + 3) < inend) {
744 if (mpeg_parse_header (mpeg, inptr) && mpeg->bit_rate) {
745 /* validate that this is really an MPEG frame header by calculating the
746 * position of the next frame header and checking that it looks like a
747 * valid frame header too */
748 len = (guint32) mpeg_frame_length (mpeg, false);
749 pos = source->GetPosition ();
751 if (vbr && mpeg_check_vbr_headers (mpeg, vbr, source, offset)) {
752 if (vbr->type == MpegXingHeader)
753 len = (guint32) mpeg_frame_length (mpeg, true);
755 *result = offset + len;
756 return MEDIA_SUCCESS;
759 if (!source->IsPositionAvailable (offset + len + 4, &eof)) {
760 return eof ? MEDIA_FAIL : MEDIA_NOT_ENOUGH_DATA;
761 } else if (source->Seek (offset + len, SEEK_SET) && source->Peek (hdr, 4)) {
762 if (mpeg_parse_header (&next, hdr)) {
763 /* everything checks out A-OK */
764 *result = offset;
765 return MEDIA_SUCCESS;
769 /* restore state */
770 if (pos == -1 || !source->Seek (pos, SEEK_SET))
771 return MEDIA_FAIL;
774 /* not an mpeg audio sync header */
775 offset++;
776 inptr++;
777 } else {
778 /* not enough data to check */
779 break;
781 } while (inptr < inend);
783 if ((n = (inend - inptr)) > 0) {
784 /* save the remaining bytes */
785 memmove (buf, inptr, n);
788 /* if we scan more than 'MPEG_FRAME_LENGTH_MAX' bytes, this is unlikely to be an mpeg audio stream */
789 } while ((offset - start) < MPEG_FRAME_LENGTH_MAX);
791 return MEDIA_FAIL;
794 void
795 Mp3Demuxer::OpenDemuxerAsyncInternal ()
797 MediaResult result;
799 LOG_MP3 ("Mp3Demuxer::OpenDemuxerAsyncInternal ()\n");
801 result = ReadHeader ();
803 if (MEDIA_SUCCEEDED (result)) {
804 ReportOpenDemuxerCompleted ();
805 } else {
806 ReportErrorOccurred (result);
810 MediaResult
811 Mp3Demuxer::ReadHeader ()
813 LOG_MP3 ("Mp3Demuxer::ReadHeader ()\n");
815 MediaResult result;
816 IMediaStream **streams = NULL;
817 gint64 stream_start;
818 gint64 header_start = -1;
819 IMediaStream *stream;
820 MpegFrameHeader mpeg;
821 AudioStream *audio;
822 Media *media;
823 guint8 buffer[10];
824 MpegVBRHeader vbr;
825 guint64 duration;
826 guint32 size = 0;
827 double nframes;
828 int stream_count;
829 double len;
830 gint64 end;
831 int i;
832 bool eof = false;
834 if (!source->IsPositionAvailable (10, &eof))
835 return eof ? MEDIA_FAIL : MEDIA_NOT_ENOUGH_DATA;
837 if (!source->Peek (buffer, 10))
838 return MEDIA_INVALID_MEDIA;
840 // Check for a leading ID3 tag
841 if (!strncmp ((const char *) buffer, "ID3", 3)) {
842 for (i = 0; i < 4; i++) {
843 if (buffer[6 + i] & 0x80)
844 return MEDIA_INVALID_MEDIA;
846 size = (size << 7) | buffer[6 + i];
849 if ((buffer[5] & (1 << 4))) {
850 // add additional 10 bytes for footer
851 size += 20;
852 } else
853 size += 10;
855 // MPEG stream data starts at the end of the ID3 tag
856 stream_start = (gint64) size;
857 } else {
858 stream_start = 0;
861 // There can be an "arbitrary" amount of garbage at the
862 // beginning of an mp3 stream, so we need to find the first
863 // MPEG sync header by scanning.
864 vbr.type = MpegNoVBRHeader;
865 if (!MEDIA_SUCCEEDED (result = Mp3FrameReader::FindMpegHeader (&mpeg, &vbr, source, stream_start, &header_start))) {
866 source->Seek (0, SEEK_SET);
867 return result;
870 stream_start = header_start;
872 if (!source->Seek (stream_start, SEEK_SET))
873 return MEDIA_INVALID_MEDIA;
875 if (vbr.type == MpegNoVBRHeader) {
876 // calculate the frame length
877 len = mpeg_frame_length (&mpeg, false);
879 if ((end = source->GetSize ()) != -1) {
880 // estimate the number of frames
881 nframes = ((double) end - (double) stream_start) / (double) len;
882 } else {
883 nframes = 0;
885 } else {
886 if (vbr.type == MpegXingHeader)
887 xing = true;
889 // calculate the frame length
890 len = mpeg_frame_length (&mpeg, xing);
891 nframes = vbr.nframes;
894 // calculate the duration of the first frame
895 duration = mpeg_frame_duration (&mpeg);
897 media = GetMediaReffed ();
898 stream = audio = new AudioStream (media);
899 media->unref ();
900 media = NULL;
901 reader = new Mp3FrameReader (source, audio, stream_start, len, duration, xing);
903 audio->codec_id = CODEC_MP3;
904 audio->codec = g_strdup ("mp3");
906 audio->duration = duration * nframes;
907 audio->SetBitRate (mpeg.bit_rate);
908 audio->SetChannels (mpeg.channels);
909 audio->SetSampleRate (mpeg.sample_rate);
910 audio->SetBlockAlign (mpeg_block_size (&mpeg));
911 audio->SetBitsPerSample (mpeg.layer == 1 ? 32 : 8);
912 audio->SetExtraData (NULL);
913 audio->SetExtraDataSize (0);
915 streams = g_new (IMediaStream *, 2);
916 streams[0] = stream;
917 streams[1] = NULL;
918 stream_count = 1;
920 SetStreams (streams, stream_count);
921 stream->unref ();
923 return MEDIA_SUCCESS;
926 MediaResult
927 Mp3Demuxer::GetFrameCallback (MediaClosure *c)
929 MediaGetFrameClosure *closure = (MediaGetFrameClosure *) c;
930 ((Mp3Demuxer *) closure->GetDemuxer ())->GetFrameAsyncInternal (closure->GetStream ());
931 return MEDIA_SUCCESS;
934 void
935 Mp3Demuxer::GetFrameAsyncInternal (IMediaStream *stream)
937 MediaFrame *frame = NULL;
938 MediaResult result;
940 result = reader->TryReadFrame (&frame);
942 if (result == MEDIA_DEMUXER_ERROR || result == MEDIA_BUFFER_UNDERFLOW || result == MEDIA_DEMUXER_ERROR || result == MEDIA_NOT_ENOUGH_DATA) {
943 Media *media = GetMediaReffed ();
944 g_return_if_fail (media != NULL);
945 MediaGetFrameClosure *closure = new MediaGetFrameClosure (media, GetFrameCallback, this, stream);
946 media->EnqueueWork (closure, false);
947 closure->unref ();
948 media->unref ();
949 return;
952 if (result == MEDIA_NO_MORE_DATA) {
953 ReportGetFrameCompleted (NULL);
954 } else if (MEDIA_SUCCEEDED (result)) {
955 ReportGetFrameCompleted (frame);
956 } else {
957 ReportErrorOccurred (result);
960 if (frame)
961 frame->unref ();
965 * Mp3DemuxerInfo
968 MediaResult
969 Mp3DemuxerInfo::Supports (IMediaSource *source)
971 MediaResult result;
972 gint64 stream_start = 0;
973 gint64 header_start = 0;
974 MpegFrameHeader mpeg;
975 guint8 buffer[10];
976 guint32 size = 0;
977 MpegVBRHeader vbr;
978 int i;
980 // peek at the first 10 bytes which is enough to contain
981 // either the mp3 frame header or an ID3 tag header
982 if (!source->Peek (buffer, 10))
983 return MEDIA_FAIL;
985 // Check for a leading ID3 tag
986 if (!strncmp ((const char *) buffer, "ID3", 3)) {
987 for (i = 0; i < 4; i++) {
988 if (buffer[6 + i] & 0x80)
989 return MEDIA_FAIL;
991 size = (size << 7) | buffer[6 + i];
994 if ((buffer[5] & (1 << 4))) {
995 // add additional 10 bytes for footer
996 size += 20;
997 } else
998 size += 10;
1000 // skip over the ID3 tag
1001 stream_start = (gint64) size;
1004 result = Mp3FrameReader::FindMpegHeader (&mpeg, &vbr, source, stream_start, &header_start);
1006 source->Seek (0, SEEK_SET);
1008 LOG_MP3 ("Mp3DemuxerInfo::Supports (%p) result: %i\n", source, result);
1010 return result;
1013 IMediaDemuxer *
1014 Mp3DemuxerInfo::Create (Media *media, IMediaSource *source)
1016 return new Mp3Demuxer (media, source);