/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.media.mpegts.packet; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import com.ttProject.media.extra.Bit; import com.ttProject.media.extra.Bit3; import com.ttProject.media.extra.Bit4; import com.ttProject.media.extra.Bit5; import com.ttProject.media.extra.Bit8; import com.ttProject.media.extra.BitLoader; import com.ttProject.media.mpegts.ProgramPacket; import com.ttProject.media.mpegts.field.PmtElementaryField; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.nio.channels.IReadChannel; /** * Pmt * marioの * 47500010 * 0002B0170001C10000 * E100F000 * 1BE100F000(h264) * 0FE101F000(aac) * 2F44B99B(CRC32) * * rtypeDelta aacのみになったやつ * 47500010 * 0002B0120001C10000 * E100F000 * 0FE100F000(aac) * B69BC0D9(CRC32) * * * vlcが出力したデータ * 474042309500FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF * [ ]ここまでは普通 * []adaptationfieldで埋めてある。 * 0002B01E0001E30000(programPacketで共通化している部分) * []tableId 2 * [ ]sectionLength * [ ]programNumber 1 * [] version numberが0x11になってる。 * [ ] lastSectionNumberが0ではない * E044F000 * [ ] pcrPidが0x44 * [ ]ふつう * 81E044F00C 050441432D330A0400000000(1トラック分しかないじゃんw) * 81ED7715(crc32) * * 0002B01E0001E30000E044F00081E044F00C050441432D330A040000000081ED7715 * 0002B01E0001E30000E044F00081E044F00C050441432D330A040000000081ED7715 * 0002B01E0001E30000E044F00081E044F00C050441432D330A040000000081ED7715 * * 途中から長さがかわってた。始めは1Bのデータ(h264のデータが追加されてますね。) * 0002B0290001E50000E045F00081E044F00C050441432D330A04000000001BE045F0060A040000000097DACB3E * 0002B0290001E50000 * E045F000 * 81E044F00C 05 04 41432D33 0A 04 00000000 * [1B]E045F006 0A 04 00000000 * 97DACB3E * @author taktod */ public class Pmt extends ProgramPacket { /** 巡回データカウンター */ private static byte counter = 0; private short pmtPid = 0x1000; // pmtのpid値 private Bit3 reserved1; private short pcrPid; // 13bit private Bit4 reserved2; private short programInfoLength; // 12bit (どうみてもこれ0なんだが・・・どうなるんだろう) private List<PmtElementaryField> fields = new ArrayList<PmtElementaryField>(); // 以下programDescriptor // type 3bit pid 4bit esInfoLength eDescriptor public Pmt() throws Exception { super(0); setupDefault(); } public Pmt(short pid) throws Exception { super(0); pmtPid = pid; setupDefault(); } public Pmt(ByteBuffer buffer) throws Exception { this(0, buffer); } public Pmt(int position, ByteBuffer buffer) throws Exception { super(position); analyze(new ByteReadChannel(buffer)); } @Override public void setupDefault() throws Exception { byte b1 = (byte)(0x40 | (pmtPid >>> 8)); byte b2 = (byte)(pmtPid & 0xFF); analyzeHeader(new ByteReadChannel(new byte[]{ 0x47, b1, b2, 0x10, 0x00, 0x02, (byte)0xB0, 0x0D, 0x00, 0x01, (byte)0xC1, 0x00, 0x00 })); reserved1 = new Bit3(0x07); pcrPid = 0x0100; // トラックは0x0100〜はじめるとして、一番目が固定でpcrになるようにしておく。 reserved2 = new Bit4(0x0F); programInfoLength = 0; // あとはトラック情報なんだが、そこはコーデック情報依存なので、あとでなんとかしておく。 } @Override public List<Bit> getBits() { List<Bit> list = super.getBits(); list.add(reserved1); list.add(new Bit5(pcrPid >>> 8)); list.add(new Bit8(pcrPid)); list.add(reserved2); list.add(new Bit4(programInfoLength >>> 8)); list.add(new Bit8(programInfoLength)); for(PmtElementaryField pefield : fields) { list.addAll(pefield.getBits()); } return list; } public void addNewField(PmtElementaryField field) { if(!fields.contains(field)) { fields.add(field); // 追加したらデータの計算しなおしを実行する必要あり。 short length = 0; // programPacket由来 length += 5; // pmtのデータ length += 4; // fieldの長さ for(PmtElementaryField elementaryField : fields) { length += (short)elementaryField.getSize(); } // crc32 length += 4; setSectionLength(length); } } @Override public void analyze(IReadChannel ch) throws Exception { analyzeHeader(ch); pmtPid = getPid(); int size = getSectionLength() - 5; // 残りの読み込むべきデータ量 // 自分のデータを読み込む reserved1 = new Bit3(); Bit5 pcrPid_1 = new Bit5(); Bit8 pcrPid_2 = new Bit8(); reserved2 = new Bit4(); Bit4 programInfoLength_1 = new Bit4(); Bit8 programInfoLength_2 = new Bit8(); BitLoader bitLoader = new BitLoader(ch); bitLoader.load(reserved1, pcrPid_1, pcrPid_2, reserved2, programInfoLength_1, programInfoLength_2); pcrPid = (short)((pcrPid_1.get() << 8) | pcrPid_2.get()); programInfoLength = (short)((programInfoLength_1.get() << 8) | programInfoLength_2.get()); // sectionLengthから残りのデータ量を見積もる。 size -= 4; while(size > 4) { // 残りの部分がpmtElementaryFieldになる。 PmtElementaryField elementaryField = new PmtElementaryField(); elementaryField.analyze(ch); size -= elementaryField.getSize(); fields.add(elementaryField); } } public short getPcrPid() { return pcrPid; } public void setPcrPid(short pcrPid) { this.pcrPid = pcrPid; } public List<PmtElementaryField> getFields() { return new ArrayList<PmtElementaryField>(fields); } @Override public ByteBuffer getBuffer() throws Exception { setContinuityCounter(counter ++); return super.getBuffer(); } /** * 巡回cc値を設定して動作するgetBuffer * @param counter * @return * @throws Exception */ public ByteBuffer getBuffer(int counter) throws Exception { setContinuityCounter(counter); return super.getBuffer(); } @Override public String toString() { StringBuilder data = new StringBuilder(); data.append("Pmt:"); data.append("\n").append(super.toString()); data.append(" r1:").append(reserved1); data.append(" pp:").append(Integer.toHexString(pcrPid)); data.append(" r2:").append(reserved2); data.append(" pil:").append(Integer.toHexString(programInfoLength)); // あとはfieldのデータ for(PmtElementaryField pefield : fields) { data.append("\n"); data.append(pefield); } return data.toString(); } }