/*
* Java port of ffmpeg MPEG demultiplexer.
* Copyright (c) 2003 Jonathan Hueber.
*
* Copyright (c) 2000, 2001 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* See Credits file and Readme for details
* 1a39e335700bec46ae31a38e2156a898
*/
package net.sourceforge.jffmpeg.demux.mpg;
import javax.media.Demultiplexer;
import javax.media.protocol.Positionable;
import javax.media.protocol.Seekable;
import javax.media.Time;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.FileTypeDescriptor;
import javax.media.Track;
import javax.media.protocol.DataSource;
import javax.media.protocol.PullDataSource;
import javax.media.protocol.PullSourceStream;
import javax.media.MediaLocator;
import javax.media.BadHeaderException;
import javax.media.Buffer;
import javax.media.Format;
import javax.media.format.AudioFormat;
import javax.media.format.VideoFormat;
import javax.media.TrackListener;
import java.io.IOException;
import java.util.HashMap;
import java.util.Enumeration;
import java.awt.Dimension;
/**
* Mpeg Track implementation. Reads an MPEG stream
*/
public class MpegVideoTrack extends MpegTrack {
/**
* Constructor - pass Track Identifier
*/
public MpegVideoTrack( MpegDemux demux, int trackId ) {
super( demux, trackId );
}
/**
* Return Audio format
*/
public Format getFormat() {
if ( !parsedHeader ) {
try {
parseHeader();
} catch ( IOException e ) {
}
}
return format;
}
/**
* Header information
*/
private boolean parsedHeader = false;
private Buffer header = new Buffer();
/**
* Mpeg Frame rate conversion
*/
private float[] frameRateTable = new float[] {
0, (float)24000/1001, 24, 25,
(float)30000/1001, 30, 50, (float)60000/1001,
60, 15, 5, 10, 12, 15, 0
};
/**
* Read Header information
*/
protected synchronized void parseHeader() throws IOException {
long firstMpeg2Packet = 0;
int width = 0;
int height = 0;
float frameRate = 0.0f;
/**
* Parse Header packets
*/
while ( !parsedHeader ) {
/**
* Read Packet Identifier
*/
int packetID = demux.peekPacket( pos );
/**
* Check this is a header packet
*/
if ( packetID < 0x1b0 ) {
parsedHeader = true;
break;
}
/**
* Embedded Stream -- MPEG2
*/
if ( ((packetID >= 0x1c0 && packetID <= 0x1df) ||
(packetID >= 0x1e0 && packetID <= 0x1ef) ||
(packetID == 0x1bd))) {
/**
* Enter video stream
*/
firstMpeg2Packet = pos;
pos = demux.readDTSHeader( header, pos );
continue;
}
/**
* Read Header Packet
*/
int pointer = header.getLength() + 4;
/**
* Sequence Start code
*/
if ( packetID == MpegDemux.SEQUENCE_START_CODE ) {
/**
* Get Width/Hight/Frame rate
*/
pos = demux.readPacket( header, trackId, pos );
byte[] packet = (byte[])header.getData();
width = ((packet[ pointer ] & 0xff) << 4)
| ((packet[ pointer + 1 ] >>4) &0xf);
height = ((packet[ pointer + 1 ] & 0xf) << 8)
| ((packet[ pointer + 2 ]) & 0xff);
int frame_rate_index = packet[ pointer + 3 ] & 0xf;
frameRate = frameRateTable[ frame_rate_index ];
format = new VideoFormat( "mpeg", new Dimension(width,height),
10000, (new byte[1]).getClass(),
frameRate );
} else if ( packetID == MpegDemux.EXT_START_CODE ) {
/**
* MPEG 2 Extension
*/
pos = demux.readPacket( header, trackId, pos );
byte[] packet = (byte[])header.getData();
int extensionCode = (packet[pointer]>>4) & 0xf;
/* Sequence Extension */
if ( extensionCode == 1 ) {
width |= ((packet[pointer+1]&0x1)<<12)
|((packet[pointer+2]&0x80)<<3);
height |= ((packet[pointer+2]&0xa0)<<5);
format = new VideoFormat( "mpeg", new Dimension(width,height),
10000, (new byte[1]).getClass(),
frameRate );
}
} else {
/* Not a recognised header packet */
int p = header.getLength();
pos = demux.readPacket( header, trackId, pos );
header.setLength(p);
}
}
/**
* Exit Mpeg 2 packet
*/
if ( firstMpeg2Packet != 0 ) {
pos = firstMpeg2Packet;
}
}
/**
* Return a buffer containing audio data
*/
public void readFrame(Buffer buffer) {
// if ( trackId == MpegDemux.AUDIO ) return;
try {
/** First things first -- Read headers */
if (!parsedHeader) parseHeader();
/** Allocate buffer */
byte[] buf = (byte[])buffer.getData();
if ( buf == null || buf.length < 100000 ) {
buf = new byte[ 1000000 ];
buffer.setData( buf );
}
buffer.setLength(0);
buffer.setOffset( 0 );
/** Loop until we have a "trackId" packet */
boolean gotPacket = false;
while (!gotPacket) {
/* Look at the next packet */
int startcode = demux.peekPacket( pos );
// System.out.println( trackId + " " + Long.toHexString(pos) + ": " +Integer.toHexString( startcode ) );
/* Is this a DTS/PTS type packet (Mpeg2)? */
if ( ((startcode >= 0x1c0 && startcode <= 0x1df) ||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
(startcode == 0x1bd))) {
/** Is this the right kind of DTS/PTS packet? */
if ( startcode != trackId )
{
pos = demux.skipDTSPacket( pos );
continue;
}
pos = demux.readDTSHeader( buffer, pos );
continue;
}
/* This is an MPEG1 type packet */
if ( startcode == MpegDemux.SEQUENCE_END_CODE ) {
/* End of file */
buffer.setEOM( true );
}
if ( startcode == MpegDemux.SEQUENCE_END_CODE
|| startcode == MpegDemux.GOP_START_CODE ) {
/* End of Group Of Pictures */
gotPacket = true;
pos = demux.skipPacket( pos );
break;
}
if ( startcode == MpegDemux.PACK_START_CODE ) {
/* Audio packet */
if ( trackId == startcode ) {
pos = demux.readPacket( buffer, trackId, pos + 4 );
gotPacket = true;
} else {
pos = demux.skipPacket( pos );
}
} else {
/* Video Packet */
/* MPEGI video tracks all start with a header */
if ( buffer.getLength() == 0 ) {
byte[] buff = (byte[])buffer.getData();
buffer.setLength( header.getLength() );
buffer.setOffset( 0 );
System.arraycopy( header.getData(), 0, buff, 0, header.getLength() );
}
pos = demux.readPacket( buffer, trackId, pos );
}
}
// System.out.println( "Got packet" );
/* Set buffer information */
buffer.setFlags( Buffer.FLAG_NO_WAIT );
} catch( Exception e ) {
e.printStackTrace();
}
}
}