Exemplo n.º 1
0
static void
mpeg_print_info (MpegFrameHeader *mpeg)
{
	const char *version;
	
	switch (mpeg->version) {
	case 1:
		version = "1";
		break;
	case 2:
		version = "2";
		break;
	default:
		version = "2.5";
		break;
	}
	
	printf ("MPEG-%s Audio Layer %d; %d Hz, %d ch, %d kbit\n",
		version, mpeg->layer, mpeg->sample_rate, mpeg->channels,
		mpeg->bit_rate / 1000);
	
	printf ("\t16bit crc=%s; padded=%s\n", mpeg->prot ? "true" : "false",
		mpeg->padded ? "true" : "false");
	
	printf ("\tframe length = %u bytes\n", mpeg_frame_length (mpeg, false));
}
Exemplo n.º 2
0
static bool
mpeg_check_vbr_headers (MpegFrameHeader *mpeg, MpegVBRHeader *vbr, guint8 *inptr, guint32 n)
{
	guint32 nframes = 0, size = 0;
	double len;
	guint8 *buffer;
	guint8 *bufptr;
	gint64 offset;
	int i;
	
	// first, check for a Xing header
	offset = mpeg_xing_header_offset (mpeg);
	if (offset + 16 <= n) {
		buffer = inptr + offset;
		if (!strncmp ((const char *) buffer, "Xing", 4)) {
			if (buffer [7] & 0x01) {
				// decode the number of frames
				nframes = (buffer [8] << 24) + (buffer [9] << 16) + (buffer [10] << 8) + buffer [11];
			} else if (buffer [7] & 0x02) {
				size = (buffer [8] << 24) + (buffer [9] << 16) + (buffer [10] << 8) + buffer [11];
				
				// calculate the frame length
				len = mpeg_frame_length (mpeg);
				
				// estimate the number of frames
				nframes = size / len;
			}
			
			vbr->type = MpegXingHeader;
			vbr->nframes = nframes;
			
			return true;
		}
	}
	
	// check for a Fraunhofer VBRI header
	offset = mpeg_vbri_header_offset;
	if (offset + 24 <= n) {
		buffer = inptr + offset;	
		if (!strncmp ((const char *) buffer, "VBRI", 4)) {
			// decode the number of frames
			bufptr = buffer + 14;
			for (i = 0; i < 4; i++)
				nframes = (nframes << 8) | *bufptr++;
			
			vbr->type = MpegVBRIHeader;
			vbr->nframes = nframes;
			
			return true;
		}
	}
	
	return false;
}
Exemplo n.º 3
0
Arquivo: mp3.c Projeto: hjelmn/upod
static int mp3_scan (struct mp3_file *mp3) {
  int header;
  int ret;
  int frames = 0;
  int last_bitrate = -1;
  int total_framesize = 0;

  size_t bitrate;
  int frame_size;

  mp3_debug ("mp3_scan: Entering...\n");

  if (mp3->frames == 0 || mp3->xdata_size == 0) {
    /* This calculation will (from time to time) produce a duration that does not agree with the
       value produced by itunes. */
    while (ftell (mp3->fh) < mp3->data_size && (frames < FRAME_COUNT || mp3->vbr)) {
      fread (&header, 4, 1, mp3->fh);

      header = big32_2_arch32 (header);
      
      if (check_mp3_header (header) != 0) {
	fseek (mp3->fh, -4, SEEK_CUR);

	mp3_debug ("mp3_scan: Invalid header %08x %08x Bytes into the file.\n", header, ftell(mp3->fh));
	
	if ((ret = find_first_frame (mp3)) == -1) {
	  mp3_debug ("mp3_scan: An error occured at line: %i\n", __LINE__);
	  
	  /* This is hack-ish, but there might be junk at the end of the file. */
	  
	  break;
	} else if (ret == -2) {
	  mp3_debug ("mp3_scan: Ran into MLLT frame.\n");
	  
	  mp3->data_size -= (mp3->file_size) - ftell (mp3->fh);
	  
	  break;
	}
	
	continue;
      }
      
      bitrate = BITRATE(header);
      
      if (!mp3->vbr && (last_bitrate != -1) && (bitrate != last_bitrate))
	mp3->vbr = 1;
      else
	last_bitrate = bitrate;
      
      frame_size = mpeg_frame_length (header);
      total_framesize += frame_size;
      fseek (mp3->fh, frame_size - 4, SEEK_CUR);      
      frames++;
    }

    /* approximate the number of frames in the file */
    if (frames == FRAME_COUNT) {
      frames = (int)((double)((mp3->data_size - mp3->tagv2_size) * FRAME_COUNT) / (double)total_framesize);
      total_framesize = mp3->data_size - mp3->tagv2_size;
    }

    if (mp3->frames == 0)
      mp3->frames = frames;

    if (mp3->xdata_size == 0)
      mp3->xdata_size = total_framesize;
  }

  /* duration (ms) = frames * ms/sec * (samples/frame)/(samples/sec) */
  mp3->samples    = (long long)samples_per_frame[mp3->version_index][mp3->layer_index] * (long long)mp3->frames;
  mp3->duration   = (int)(1000.0 * (double)mp3->samples/(double)mp3->samplerate);
  mp3->bitrate    = (int)(((float)mp3->xdata_size * 8.0)/(float)mp3->duration);

  mp3_debug ("mp3_scan: Finished scan. SampleRate: %i, BitRate: %i, Length: %i, Frames: %i.\n",
	     mp3->samplerate, mp3->bitrate, mp3->duration, mp3->frames);

  if (mp3->samplerate <= 0 || mp3->bitrate <= 0 || mp3->duration <= 0)
    return -1;

  return 0;
}
Exemplo n.º 4
0
void
Mp3Demuxer::OpenDemuxer (MemoryBuffer *open_source)
{
	LOG_MP3 ("Mp3Demuxer::OpenDemuxer ()\n");

	IMediaStream **streams = NULL;
	IMediaStream *stream;
	MpegFrameHeader mpeg;
	gint64 stream_start;
	AudioStream *audio;
	Media *media;
	guint8 buffer [10];
	MpegVBRHeader vbr;
	guint64 duration;
	guint32 size = 0;
	double nframes;
	int stream_count;
	double len;
	gint64 end;
	int i;

	if (open_source == NULL) {
		/* No data read yet, request a read */
		if (!RequestMoreData (OpenDemuxerCallback))
			ReportErrorOccurred ("Could not open Mp3 demuxer: unexpected end of data.");
		return;
	}

	if (open_source->GetSize () < 10) {
		/* Not enough data read, request more */
		if (!RequestMoreData (OpenDemuxerCallback))
			ReportErrorOccurred ("Could not open Mp3 demuxer: data stream ended early.");
		return;
	}
	
	if (!open_source->Peek (buffer, 10)) {
		/* This shouldn't fail */
		ReportErrorOccurred ("Could not open Mp3 demuxer: peek error.");
		return;
	}

	// Check for a leading ID3 tag
	if (!strncmp ((const char *) buffer, "ID3", 3)) {
		for (i = 0; i < 4; i++) {
			if (buffer[6 + i] & 0x80) {
				ReportErrorOccurred ("Could not open Mp3 demuxer: invalid ID3 tag.");
				return;
			}
			
			size = (size << 7) | buffer[6 + i];
		}
		
		if ((buffer[5] & (1 << 4))) {
			// add additional 10 bytes for footer
			size += 20;
		} else
			size += 10;
		
		// MPEG stream data starts at the end of the ID3 tag
		stream_start = (gint64) size;
	} else {
		stream_start = 0;
	}
	
	/* Seek to the stream start */
	if (stream_start > 0) {
		/* We're still at position 0, so no need to do anything if stream_start is also 0 */
		if (stream_start > open_source->GetSize ()) {
			/* Not enough data, request more */
			if (!RequestMoreData (OpenDemuxerCallback)) {
				ReportErrorOccurred ("Could not open Mp3 demuxer: could not seek to end of ID3 tag.");
				return;
			}
		}
		open_source->SeekOffset (stream_start);
	}

	// There can be an "arbitrary" amount of garbage at the
	// beginning of an mp3 stream, so we need to find the first
	// MPEG sync header by scanning.
	vbr.type = MpegNoVBRHeader;
	if (!Mp3FrameReader::FindMpegHeader (&mpeg, &vbr, open_source)) {
		/* Could not find a header with the available data */
		/* Seek back to 0, read more data, and try again */
		/* TODO: store the current state and only read new data to avoid seeking back here */
		open_source->SeekSet (0);
		if (!RequestMoreData (OpenDemuxerCallback)) {
			/* This should not happen, we should be able to seek back to 0 */
			ReportErrorOccurred ("Could not open Mp3 demuxer: error while seeking to start point.");
		}
		
		return;
	}

	if (vbr.type == MpegNoVBRHeader) {
		// calculate the frame length
		len = mpeg_frame_length (&mpeg);
		
		if ((end = source->GetSize ()) != -1) {
			// estimate the number of frames
			nframes = ((double) end - (double) stream_start) / (double) len;
		} else {
			nframes = 0;
		}
	} else {
		// calculate the frame length
		len = mpeg_frame_length (&mpeg);
		nframes = vbr.nframes;
	}
	
	// calculate the duration of the first frame
	duration = mpeg_frame_duration (&mpeg);
	
	media = GetMediaReffed ();	
	stream = audio = new AudioStream (media);
	media->unref ();
	media = NULL;
	reader = new Mp3FrameReader (this, source, audio, stream_start, len, duration, nframes);
	
	audio->SetCodecId (CODEC_MP3);
	audio->SetDuration (duration * nframes);
	audio->SetBitRate (mpeg.bit_rate);
	audio->SetChannels (mpeg.channels);
	audio->SetSampleRate (mpeg.sample_rate);
	audio->SetBlockAlign (mpeg_block_size (&mpeg));
	audio->SetBitsPerSample (mpeg.layer == 1 ? 32 : 8);
	audio->SetExtraData (NULL);
	audio->SetExtraDataSize (0);
	
	streams = g_new (IMediaStream *, 2);
	streams[0] = stream;
	streams[1] = NULL;
	stream_count = 1;
	
	SetStreams (streams, stream_count);
	stream->unref ();
	
	this->current_source = open_source;
	this->current_source->ref ();

	LOG_MP3 ("Mp3Demuxer::OpenDemuxer (): Version: %s Layer: %u VBR: %s Duration: %" G_GUINT64_FORMAT " ms Bit rate: %u Channels: %u Sample Rate: %u Block Align: %u Bits per sample: %u Number of frames: %.2f Frame length: %.2f\n",
		mpeg.version == 3 ? "2.5" : (mpeg.version == 2 ? "2" : "1"), mpeg.layer, vbr.type == MpegNoVBRHeader ? "No" : (vbr.type == MpegXingHeader ? "Xing" : "VBRI"), MilliSeconds_FromPts (audio->GetDuration ()), audio->GetBitRate (), audio->GetChannels (), audio->GetSampleRate (), audio->GetBlockAlign (), audio->GetBitsPerSample (), nframes, len);
		
	ReportOpenDemuxerCompleted ();
}
Exemplo n.º 5
0
bool
Mp3FrameReader::FindMpegHeader (MpegFrameHeader *mpeg, MpegVBRHeader *vbr, MemoryBuffer *source)
{
	guint8 *inbuf, *inend;
	gint64 offset = 0;
	guint8 *inptr;
	MpegFrameHeader next;
	guint32 n = 0;
	guint32 len;
	
	n = source->GetRemainingSize ();

	LOG_MP3 ("Mp3FrameReader::FindMpegHeader (): %u bytes in buffer\n", n);

	if (n < 4) {
		/* Not enough data left */
		LOG_MP3 ("Mp3FrameReader::FindMpegHeader (): Failed (less than 4 bytes available).\n");
		return false;
	}

	inbuf = (guint8 *) source->GetCurrentPtr ();
	inend = inbuf + n;
	inptr = inbuf;

	do {
		/* mpeg audio sync header begins with a 0xff */
		while (inptr < inend && *inptr != 0xff) {
			offset++;
			inptr++;
		}
		
		if (offset > 0) {
			/* Discard data we've already passed by */
			source->SeekOffset (offset);
			n -= offset;
			offset = 0;
		}

		if (n < 4) {
			/* Not enough data left */
			LOG_MP3 ("Mp3FrameReader::FindMpegHeader (): Failed (less than 4 bytes left).\n");
			return false;
		}
		
		/* found a 0xff byte... could be a frame header */
		if (mpeg_parse_header (mpeg, inptr) && mpeg->bit_rate) {
			/* validate that this is really an MPEG frame header by calculating the
			 * position of the next frame header and checking that it looks like a
			 * valid frame header too */
			
			if (vbr && mpeg_check_vbr_headers (mpeg, vbr, inptr, n)) {
				/* It's a vbr frame, no need to check the next frame, this check is good enough */
				return true;
			}

			len = (guint32) mpeg_frame_length (mpeg);

			if (n == len) {
				/* The last frame in the file, there is no next frame */
				/* TODO: maybe add a check for a real eof here? */
				return true;
			}

			if (n < len + 4) {
				/* Not enough data */
				LOG_MP3 ("Mp3FrameReader::FindMpegHeader (): Failed (entire frame isn't available (%u bytes for frame, %u bytes available))\n", len + 4, n);
				return false;
			}

			/* Try to parse the memory where the next header would be */
			if (mpeg_parse_header (&next, inptr + len)) {
				/* everything checks out A-OK */
				return true;
			}
			
			/* Not an mpeg audio sync header, continue search */
		}
		
		/* not an mpeg audio sync header */
		offset++;
		inptr++;
	} while (inptr < inend);

	LOG_MP3 ("Mp3FrameReader::FindMpegHeader (): Failed (reached end of input buffer.\n");

	return false;
}
Exemplo n.º 6
0
void
Mp3FrameReader::ReadFrame ()
{
	MpegFrameHeader mpeg;
	guint64 duration;
	guint32 len;
	MediaFrame *frame;
	MemoryBuffer *current_source = demuxer->GetCurrentSource ();
	guint64 start_position = current_source->GetPosition ();
	
	if (!FindMpegHeader (&mpeg, NULL, current_source)) {
		LOG_MP3 ("Mp3FrameReader::ReadFrame (): Not enough data (mpeg header not found or not enough data for entire frame) - requesting more\n");
		if (!demuxer->RequestMoreData (ReadFrameCallback)) {
			/* No more data */
			LOG_MP3 ("Mp3FrameReader::ReadFrame (): reached end of stream.\n");
			demuxer->ReportGetFrameCompleted (NULL);
		}
		return;
	}

	//printf ("Mp3FrameReader::ReadFrame():\n");
	//mpeg_print_info (&mpeg);
	
	if (mpeg.bit_rate == 0) {
		// use the most recently specified bit rate
		mpeg.bit_rate = bit_rate;
	}
	
	bit_rate = mpeg.bit_rate;
	
	duration = mpeg_frame_duration (&mpeg);
	
	AddFrameIndex (demuxer->GetCurrentPosition () + current_source->GetPosition (), cur_pts, duration, bit_rate);
	
	len = (guint32) mpeg_frame_length (&mpeg);

	/* Check if we have enough data */
	if (current_source->GetRemainingSize () < len) {
		/* We need to seek back to where we started reading this frame so that the next time we're called
		 * we start parsing from the beginning again */
		current_source->SeekSet (start_position);
		
		if (!demuxer->RequestMoreData (ReadFrameCallback, MAX (len, 1024))) {
			/* No more data */
			demuxer->ReportGetFrameCompleted (NULL);
			return;
		}
		
		return;
	}

	frame = new MediaFrame (stream);
	if (!frame->AllocateBuffer (len)) {
		frame->unref ();
		return;
	}

	if (!current_source->Read (frame->GetBuffer (), len)) {
		/* This shouldn't happen, we've already checked that we have enough data */
		demuxer->ReportErrorOccurred ("Mp3Demuxer could not read from stream.");
		frame->unref ();
		return;
	}
	
	frame->pts = cur_pts;
	frame->duration = duration;
	
	frame->AddState (MediaFrameDemuxed);
	
	cur_pts += duration;
	
	demuxer->ReportGetFrameCompleted (frame);
	frame->unref ();
}