/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.packet.mpegts; import java.nio.ByteBuffer; import com.ttProject.packet.MediaPacket; @SuppressWarnings("unused") public abstract class MpegtsPacket extends MediaPacket { /** マネージャー保持 */ private final MpegtsPacketManager manager; /** 特に使わないであろうデータたち sizeはつかうか・・・ */ private int type; // 識別子 private int size; // データ長 private int versionNumber; // バージョン番号 private byte currentNextOrder; // nextOrder private int sectionNumber; // セクション番号 private int lastSectionNumber; // ラストセクション番号 /** * コンストラクタ * @param manager */ public MpegtsPacket(MpegtsPacketManager manager) { this.manager = manager; } /** * マネージャー参照 * @return */ protected MpegtsPacketManager getManager() { return manager; } /** * PIDを求める * @param buffer * @return */ protected int getPid(ByteBuffer buffer) { // なにかあったときに巻き戻すための位置取得 int position = buffer.position(); // 先頭を確認 if(buffer.get() != 0x47) { throw new RuntimeException("先頭が0x47になっていないとmpegtsとして成立していない。"); } // pid取得 int pid = buffer.getShort() & 0x1FFF; // buffer巻き戻し buffer.position(position); return pid; } /** * ヘッダの解析(たいていのデータが持っているみたいです。) * @return */ private boolean analizeHeader(ByteBuffer buffer, byte tableSignature) { if(buffer.get() != tableSignature) { // テーブルシグネチャが合いません。 return false; } int data = buffer.getShort() & 0xFFFF; if(data >>> 12 != Integer.parseInt("1011", 2)) { // セクションシンタクス指示が一致しません。 return false; } size = data &0x0FFF; type = buffer.getShort() & 0xFFFF; data = buffer.get() & 0xFF; if(data >>> 6 != Integer.parseInt("11", 2)) { // 形式がおかしい。 return false; } versionNumber = (data & 0x3F) >>> 1; currentNextOrder = (byte)(data & 0x01); sectionNumber = buffer.get() & 0xFF; lastSectionNumber = buffer.get() & 0xFF; size -= 5; return true; } /** * Patとしてデータを解析 * @param buffer * @return */ protected boolean analizePat(ByteBuffer buffer) { int position = buffer.position(); buffer.position(position + 5); // 5すすめる。 if(!analizeHeader(buffer, (byte)0x00)) { buffer.position(position); throw new RuntimeException("ヘッダ部読み込み時に不正なデータを検出しました。"); } // ディテール読み込み while(size > 4) { size -= 4; // 放送番組識別 16bit // 111 3bit (固定) // PIDデータ 13bit int data = buffer.getInt(); // 4バイト読み込む if((data & 0xF000) >>> 13 != Integer.parseInt("111", 2)) { // 固定bitが一致しない。 buffer.position(position); throw new RuntimeException("ビットフラグが一致しない。"); } if(data >>> 16 != 0) { // PMT PID // pmtなので、保持させる。 manager.addPmtId(data & 0x1FFF); } else { // ネットワークPID } } // bufferの位置を戻しておく。 buffer.position(position); return true; } /** * Pmtとしてデータを解析 * @param buffer * @return */ protected boolean analizePmt(ByteBuffer buffer) { int position = buffer.position(); buffer.position(position + 5); // 5すすめる。 if(!analizeHeader(buffer, (byte)0x02)) { buffer.position(position); throw new RuntimeException("ヘッダ部の読み込み時に不正なデータを検出しました。"); } int data; // 111 3bit(固定) // PCR_PID 13ビット 時刻主体になるパケット情報 data = buffer.getShort() & 0xFFFF; if(data >>> 13 != Integer.parseInt("111", 2)) { buffer.position(position); throw new RuntimeException("PCRPID用の指示ビットがおかしいです。"); } manager.setPcrId(data & 0x1FFF); // 1111 4bit(固定) // 番組情報長 12bit data = buffer.getShort() & 0xFFFF; if(data >>> 12 != Integer.parseInt("1111", 2)) { buffer.position(position); throw new RuntimeException("番組情報長用の指示ビットがおかしいです。"); } int skipLength = data & 0x0FFF; // 番組情報 int pos = buffer.position(); buffer.position(pos + skipLength); size -= (4 + skipLength); // 以降ストリームデータ while(size > 4) { // ストリーム形式 8bit byte type = buffer.get(); // 111 3bit // エレメンタリーPID 13bit data = buffer.getShort() & 0xFFFF; if(data >>> 13 != Integer.parseInt("111", 2)) { buffer.position(position); throw new RuntimeException("エレメンタリーID用の指示ビットがおかしいです。"); } int pid = data & 0x1FFF; if(type == 0x1B) { // h.264用のトラック manager.addH264Id(pid); } manager.addMediaId(pid); // 1111 4bit // ES情報長 12bit data = buffer.getShort() & 0xFFFF; if(data >>> 12 != Integer.parseInt("1111", 2)) { buffer.position(position); throw new RuntimeException("ES情報長用の指示ビットがおかしいです。"); } skipLength = data & 0x0FFF; // 任意 pos = buffer.position(); buffer.position(pos + skipLength); size -= (5 + skipLength); } // ポジションを戻しておく。 buffer.position(position); return true; } }