Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a bug with the MP4 parser #5

Merged
merged 1 commit into from
Sep 24, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/net/majorkernelpanic/streaming/MediaStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public boolean isStreaming() {

/** Starts the stream. */
public synchronized void start() throws IllegalStateException, IOException {

Log.d(TAG, "start");
if (mPacketizer==null)
throw new IllegalStateException("setPacketizer() should be called before start().");

Expand Down
33 changes: 20 additions & 13 deletions src/net/majorkernelpanic/streaming/mp4/MP4Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

package net.majorkernelpanic.streaming.mp4;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.HashMap;

import android.util.Base64;
Expand All @@ -40,7 +40,6 @@ class MP4Parser {
private HashMap<String, Long> boxes = new HashMap<String, Long>();
private final RandomAccessFile file;
private long pos = 0;
private byte[] buffer = new byte[8];

public MP4Parser(final String path) throws IOException, FileNotFoundException {
this.file = new RandomAccessFile(new File(path), "r");
Expand Down Expand Up @@ -85,20 +84,26 @@ public StsdBox getStsdBox() throws IOException {
}

private void parse(String path, long len) throws IOException {
byte[] buffer = new byte[8];
String name="";
long sum = 0, newlen = 0;

boxes.put(path, pos-8);
if(!path.equals(""))
boxes.put(path, pos-8);


while (sum<len) {

file.read(buffer,0,8); sum += 8; pos += 8;
if (validBoxName()) {

newlen = ( buffer[3]&0xFF | (buffer[2]&0xFF)<<8 | (buffer[1]&0xFF)<<16 | (buffer[0]&0xFF)<<24 ) - 8;
// 1061109559+8 correspond to "????" in ASCII the HTC Desire S seems to write that sometimes, maybe other phones do
if (newlen<=0 || newlen==1061109559) throw new IOException();
file.read(buffer,0,8);
sum += 8;
pos += 8;
if (validBoxName(buffer)) {

ByteBuffer byteBuffer = ByteBuffer.wrap(buffer,0,4);
newlen = byteBuffer.getInt()-8;

// a) 1061109559+8 correspond to "????" in ASCII the HTC Desire S seems to write that sometimes, maybe other phones do
// b) wide atom would produce a newlen == 0, and we shouldn't throw an exception because of that
if (newlen < 0 || newlen == 1061109559) throw new IOException();
name = new String(buffer,4,4);
Log.d(TAG,"Atom -> name: "+name+" newlen: "+newlen+" pos: "+pos);
sum += newlen;
Expand All @@ -110,7 +115,8 @@ private void parse(String path, long len) throws IOException {
file.seek(file.getFilePointer() - 8 + len);
sum += len-8;
} else {
if (file.skipBytes((int) (len-8))<len-8) {
int skipped = file.skipBytes((int)(len-8));
if (skipped < ((int)(len-8))) {
throw new IOException();
}
pos += len-8;
Expand All @@ -120,9 +126,10 @@ private void parse(String path, long len) throws IOException {
}
}

private boolean validBoxName() {
private boolean validBoxName(byte[] buffer) {
for (int i=0;i<4;i++) {
if ((buffer[i+4]<97 || buffer[i+4]>122) && (buffer[i+4]<48 || buffer[i+4]>57) ) return false;
// If the next 4 bytes are neither lowercase letters nor numbers
if ((buffer[i+4]< 'a' || buffer[i+4]>'z') && (buffer[i+4]<'0'|| buffer[i+4]>'9') ) return false;
}
return true;
}
Expand Down
15 changes: 7 additions & 8 deletions src/net/majorkernelpanic/streaming/rtsp/RtspClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,17 +182,17 @@ private void sendRequestAnnounce() throws IllegalStateException, SocketException
"Content-Length: " + body.length() + "\r\n" +
"Content-Type: application/sdp \r\n\r\n" +
body;

Log.i(TAG,request.substring(0, request.indexOf("\r\n")));

mOutputStream.write(request.getBytes("UTF-8"));
Response response = Response.parseResponse(mBufferedReader);

try {
Matcher m = Response.rexegSession.matcher(response.headers.get("session")); m.find();
Matcher m = Response.rexegSession.matcher(response.headers.get("session"));
m.find();
mSessionID = m.group(1);
} catch (Exception e) {
throw new IOException("Invalid response from server");
throw new IOException("Invalid response from server. Session id: "+mSessionID);
}

if (response.status == 401) {
Expand Down Expand Up @@ -246,17 +246,17 @@ private void sendRequestSetup() throws IllegalStateException, SocketException, I
"CSeq: " + (++mCSeq) + "\r\n" +
"Transport: RTP/AVP/UDP;unicast;client_port="+(5000+2*i)+"-"+(5000+2*i+1)+";mode=receive\r\n" +
"Session: " + mSessionID + "\r\n" +
"Authorization: " + mAuthorization+ "\r\n";
"Authorization: " + mAuthorization+ "\r\n\r\n";

Log.i(TAG,request.substring(0, request.indexOf("\r\n")));

mOutputStream.write(request.getBytes("UTF-8"));
Response response = Response.parseResponse(mBufferedReader);

Matcher m;
try {
m = Response.rexegTransport.matcher(response.headers.get("transport")); m.find();
stream.setDestinationPorts(Integer.parseInt(m.group(3)), Integer.parseInt(m.group(4)));
Log.d(TAG, "Setting destination ports: "+Integer.parseInt(m.group(3))+", "+Integer.parseInt(m.group(4)));
} catch (Exception e) {
e.printStackTrace();
int[] ports = stream.getDestinationPorts();
Expand All @@ -274,7 +274,7 @@ private void sendRequestRecord() throws IllegalStateException, SocketException,
"Range: npt=0.000-" +
"CSeq: " + (++mCSeq) + "\r\n" +
"Session: " + mSessionID + "\r\n" +
"Authorization: " + mAuthorization+ "\r\n";
"Authorization: " + mAuthorization+ "\r\n\r\n";
Log.i(TAG,request.substring(0, request.indexOf("\r\n")));
mOutputStream.write(request.getBytes("UTF-8"));
Response.parseResponse(mBufferedReader);
Expand Down Expand Up @@ -325,7 +325,7 @@ static class Response {
// Parses a WWW-Authenticate header
public static final Pattern rexegAuthenticate = Pattern.compile("realm=\"(.+)\",\\s+nonce=\"(\\w+)\"",Pattern.CASE_INSENSITIVE);
// Parses a Session header
public static final Pattern rexegSession = Pattern.compile("(\\d+);",Pattern.CASE_INSENSITIVE);
public static final Pattern rexegSession = Pattern.compile("(\\d+)",Pattern.CASE_INSENSITIVE);
// Parses a Transport header
public static final Pattern rexegTransport = Pattern.compile("client_port=(\\d+)-(\\d+).+server_port=(\\d+)-(\\d+)",Pattern.CASE_INSENSITIVE);

Expand All @@ -338,7 +338,6 @@ public static Response parseResponse(BufferedReader input) throws IOException, I
Response response = new Response();
String line;
Matcher matcher;

// Parsing request method & uri
if ((line = input.readLine())==null) throw new SocketException("Connection lost");
matcher = regexStatus.matcher(line);
Expand Down
2 changes: 1 addition & 1 deletion src/net/majorkernelpanic/streaming/video/H264Stream.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public void onInfo(MediaRecorder mr, int what, int extra) {
} else if (what==MediaRecorder.MEDIA_RECORDER_INFO_UNKNOWN) {
Log.d(TAG,"MediaRecorder: INFO_UNKNOWN");
} else {
Log.d(TAG,"WTF ?");
Log.d(TAG,"WTF ?. what: "+what);
}
mLock.release();
}
Expand Down