/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.media.mpegts.field; import java.util.ArrayList; import java.util.List; import com.ttProject.media.extra.Bit; import com.ttProject.media.extra.Bit1; import com.ttProject.media.extra.Bit6; import com.ttProject.media.extra.Bit8; import com.ttProject.media.extra.BitLoader; import com.ttProject.nio.channels.IReadChannel; /** * adaptationFieldの内容保持 * ちなみにPCRは100msec以内に一度更新してやる必要があるらしいので注意が必要。 * @author taktod */ public class AdaptationField { private Bit8 adaptationFieldLength; private Bit1 discontinuityIndicator; // 0 private Bit1 randomAccessIndicator; // aacの先頭だけ、たってる? (aacのみでも同様)(h264のキーフレームもたってるっぽい) private Bit1 elementaryStreamPriorityIndicator; // 0 private Bit1 pcrFlag; private Bit1 opcrFlag; // originalPcr(コピーするときにつかうらしい。) // 0 private Bit1 splicingPointFlag; // 0 private Bit1 transportPrivateDataFlag; // 0 private Bit1 adaptationFieldExtensionFlag; // 0 // PCR用 private long pcrBase; // 33bit 90KHz表示 private Bit6 pcrPadding; // 111111 private short pcrExtension; // 9bit 27MHz // 0 // OPCR用 private long opcrBase; // 33bit 90KHz表示 private Bit6 opcrPadding; private short opcrExtension; // 9bit 27MHz public boolean hasPcr() { return pcrFlag.get() == 1; } public long getPcrBase() { return pcrBase; } public AdaptationField() { adaptationFieldLength = new Bit8(0); discontinuityIndicator = new Bit1(0); randomAccessIndicator = new Bit1(0); elementaryStreamPriorityIndicator = new Bit1(0); pcrFlag = new Bit1(0); opcrFlag = new Bit1(0); splicingPointFlag = new Bit1(0); transportPrivateDataFlag = new Bit1(0); adaptationFieldExtensionFlag = new Bit1(0); } public void setPcrBase(long base) { pcrBase = base; } public void setRandomAccessIndicator(int flg) { // adaptationFieldの長さが存在しない場合は1に変更する必要あり。 if(adaptationFieldLength.get() == 0) { adaptationFieldLength.set(1); } randomAccessIndicator = new Bit1(flg); } // pcr opcr spliceCountdown stuffingBytes等々・・・ public void analyze(IReadChannel channel) throws Exception { // とりあえずlengthをみておく。 adaptationFieldLength = new Bit8(); BitLoader bitLoader = new BitLoader(channel); bitLoader.load(adaptationFieldLength); if(adaptationFieldLength.get() == 0x00) { return; } int size = adaptationFieldLength.get(); discontinuityIndicator = new Bit1(); randomAccessIndicator = new Bit1(); elementaryStreamPriorityIndicator = new Bit1(); pcrFlag = new Bit1(); opcrFlag = new Bit1(); splicingPointFlag = new Bit1(); transportPrivateDataFlag = new Bit1(); adaptationFieldExtensionFlag = new Bit1(); bitLoader = new BitLoader(channel); bitLoader.load(discontinuityIndicator, randomAccessIndicator, elementaryStreamPriorityIndicator, pcrFlag, opcrFlag, splicingPointFlag, transportPrivateDataFlag, adaptationFieldExtensionFlag); size --; // 他のデータがある場合は読み込んでいく必要あり。 if(pcrFlag.get() != 0x00) { // pcrがある場合 // とりあえず、つづく、33bit + 6Bit + 9Bitからデータがなるみたいです。 // 33bitの部分を90000で割るとおよそのデータ長がとれるみたい。 // はじめの33bitは90kHzでの表示、最終の9bitは27MHzでの表示となるみたいです。 // 中間の6bitはpaddingBit // とりあえずおおよそのデータがわかればよろしい感じなので、データはとっておきますが、33bitの部分からだけでデータを取得しておきます。 Bit1 pcrBase_1 = new Bit1(); Bit8 pcrBase_2 = new Bit8(); Bit8 pcrBase_3 = new Bit8(); Bit8 pcrBase_4 = new Bit8(); Bit8 pcrBase_5 = new Bit8(); pcrPadding = new Bit6(); Bit1 pcrExtension_1 = new Bit1(); Bit8 pcrExtension_2 = new Bit8(); bitLoader = new BitLoader(channel); bitLoader.load(pcrBase_1, pcrBase_2, pcrBase_3, pcrBase_4, pcrBase_5, pcrPadding, pcrExtension_1, pcrExtension_2); pcrBase = (((long)pcrBase_1.get()) << 32) | (((long)pcrBase_2.get()) << 24) | (pcrBase_3.get() << 16) | (pcrBase_4.get() << 8) | pcrBase_5.get(); pcrExtension = (short)((pcrExtension_1.get() << 8) | pcrExtension_2.get()); size -= 6; } if(opcrFlag.get() != 0x00) { // pcrと同じっぽいので実装しとく。 Bit1 opcrBase_1 = new Bit1(); Bit8 opcrBase_2 = new Bit8(); Bit8 opcrBase_3 = new Bit8(); Bit8 opcrBase_4 = new Bit8(); Bit8 opcrBase_5 = new Bit8(); opcrPadding = new Bit6(); Bit1 opcrExtension_1 = new Bit1(); Bit8 opcrExtension_2 = new Bit8(); bitLoader = new BitLoader(channel); bitLoader.load(opcrBase_1, opcrBase_2, opcrBase_3, opcrBase_4, opcrBase_5, opcrPadding, opcrExtension_1, opcrExtension_2); opcrBase = (((long)opcrBase_1.get()) << 32) | (((long)opcrBase_2.get()) << 24) | (opcrBase_3.get() << 16) | (opcrBase_4.get() << 8) | opcrBase_5.get(); opcrExtension = (short)((opcrExtension_1.get() << 8) | opcrExtension_2.get()); size -= 6; } if(splicingPointFlag.get() != 0x00) { throw new Exception("splicingPointの解析は未実装です。"); } if(transportPrivateDataFlag.get() != 0x00) { throw new Exception("transportPrivateDataの解析は未実装です。"); } if(adaptationFieldExtensionFlag.get() != 0x00) { throw new Exception("adaptationFieldExtensionの解析は未実装です。"); } if(size != 0) { // 何のフラグもなくてすべてffで埋められているっぽい。 // とりあえずスルーする必要があるっぽいが channel.position(channel.position() + size); // あいている部分はスキップしてやる必要あり。 } } /** * 長さを変更する。 * @param length */ public void setLength(int length) { adaptationFieldLength = new Bit8(length); } /** * 長さを参照する。 * @return */ public int getLength() { return adaptationFieldLength.get(); } public List<Bit> getBits() { List<Bit> list = new ArrayList<Bit>(); int length = adaptationFieldLength.get(); list.add(adaptationFieldLength); if(length == 0) { return list; } list.add(discontinuityIndicator); list.add(randomAccessIndicator); list.add(elementaryStreamPriorityIndicator); list.add(pcrFlag); list.add(opcrFlag); list.add(splicingPointFlag); list.add(transportPrivateDataFlag); list.add(adaptationFieldExtensionFlag); length --; if(pcrFlag.get() != 0x00) { list.add(new Bit1((int)(pcrBase >>> 32))); list.add(new Bit8((int)(pcrBase >>> 24))); list.add(new Bit8((int)(pcrBase >>> 16))); list.add(new Bit8((int)(pcrBase >>> 8))); list.add(new Bit8((int)(pcrBase))); list.add(pcrPadding); list.add(new Bit1(pcrExtension >>> 8)); list.add(new Bit8(pcrExtension)); length -= 6; } if(opcrFlag.get() != 0x00) { list.add(new Bit1((int)(opcrBase >>> 32))); list.add(new Bit8((int)(opcrBase >>> 24))); list.add(new Bit8((int)(opcrBase >>> 16))); list.add(new Bit8((int)(opcrBase >>> 8))); list.add(new Bit8((int)(opcrBase))); list.add(opcrPadding); list.add(new Bit1(opcrExtension >>> 8)); list.add(new Bit8(opcrExtension)); length -= 6; } for(int i = 0;i < length;i ++) { list.add(new Bit8((byte)0xFF)); } return list; } public int getRandomAccessIndicator() { return randomAccessIndicator.get(); } @Override public String toString() { StringBuilder data = new StringBuilder(); data.append(" "); data.append("adaptationField:"); data.append(" afl:").append(Integer.toHexString(adaptationFieldLength.get())); if(adaptationFieldLength.get() != 0) { data.append(" di:").append(discontinuityIndicator); data.append(" rai:").append(randomAccessIndicator); data.append(" espi:").append(elementaryStreamPriorityIndicator); data.append(" pf:").append(pcrFlag); data.append(" of:").append(opcrFlag); data.append(" spf:").append(splicingPointFlag); data.append(" tpdf:").append(transportPrivateDataFlag); data.append(" afef:").append(adaptationFieldExtensionFlag); if(pcrFlag.get() != 0x00) { data.append("[pcrBase:").append(Long.toHexString(pcrBase)) .append("(").append(pcrBase / 90000f).append("sec)"); data.append(" pcrPadding:").append(pcrPadding); data.append(" pcrExtension:").append(pcrExtension); data.append("]"); } if(opcrFlag.get() != 0x00) { data.append("[opcrBase:").append(Long.toHexString(opcrBase)) .append("(").append(opcrBase / 90000f).append("sec)"); data.append(" opcrPadding:").append(opcrPadding); data.append(" opcrExtension:").append(opcrExtension); data.append("]"); } } return data.toString(); } }