/* * 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.Bit8; import com.ttProject.media.extra.BitLoader; import com.ttProject.media.mpegts.ProgramPacket; import com.ttProject.media.mpegts.descriptor.Descriptor; import com.ttProject.media.mpegts.descriptor.ServiceDescriptor; import com.ttProject.media.mpegts.field.SdtServiceField; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.nio.channels.IReadChannel; /** * Sdt(Service Description Table) * サンプル * 474011100042F0240001C100000001FF 0001FC8013481101054C696261760953657276696365303168C5DB49 * @see http://en.wikipedia.org/wiki/Service_Description_Table * @see http://pda.etsi.org/exchangefolder/en_300468v011301p.pdf * ここでは、サービスごとに、descriptorが複数持てるようになっているみたいです。 * よって、sdtにデータをいれる場合は、serviceIdとdescriptorのデータを指定していれる必要があると思われます。 * @author taktod */ public class Sdt extends ProgramPacket { /** 巡回データカウンター */ private static byte counter = 0; // 内容データ private short originalNetworkId; // 16bit private Bit8 reservedFutureUse2; private List<SdtServiceField> serviceFields = new ArrayList<SdtServiceField>(); /** * コンストラクタ */ public Sdt() throws Exception { super(0); setupDefault(); } /** * コンストラクタ */ public Sdt(ByteBuffer buffer) throws Exception { this(0, buffer); } /** * コンストラクタ * @param position */ public Sdt(int position, ByteBuffer buffer) throws Exception { super(position); analyze(new ByteReadChannel(buffer)); } @Override public void setupDefault() throws Exception { // counterの部分が一定ではないはずなので、これではだめになる。 // payloadだけフラグをたてておく。 analyzeHeader(new ByteReadChannel(new byte[]{ 0x47, 0x40, 0x11, 0x10, // payloadだけフラグたててある。 0x00, 0x42, (byte)0xF0, 0x24, 0x00, 0x01, (byte)0xC1, 0x00, 0x00 })); originalNetworkId = 1; reservedFutureUse2 = new Bit8(0xFF); // serviceFieldの中身はあとで決める必要あり } /** * 基本と鳴るDefaultProviderデータを書き込む * @param provider * @param name */ public void writeDefaultProvider(String provider, String name) { // serviceFieldがあるか確認、1番のサービスフィールドにデータがなければ・・・ SdtServiceField targetField = null; for(SdtServiceField ssfield : serviceFields) { // serviceIdが1のデータをみつける。 if(ssfield.getServiceId() == 1) { targetField = ssfield; break; } } if(targetField == null) { targetField = new SdtServiceField(); serviceFields.add(targetField); } // 内部で保持している、descriptorsに同じproviderのdescriptorがあるか確認して、ある場合は上書き、ない場合は追加する。 ServiceDescriptor serviceDescriptor = null; for(Descriptor descriptor : targetField.getDescriptors()) { if(descriptor instanceof ServiceDescriptor) { serviceDescriptor = (ServiceDescriptor)descriptor; break; } } if(serviceDescriptor == null) { // データがセットされていない場合は上書きしてやる serviceDescriptor = new ServiceDescriptor(); } serviceDescriptor.setName(provider, name); targetField.addDescriptor(serviceDescriptor); // 変更した場合にsetSectionLengthを変更する必要あり。 short length = 0; // 5 sectionLength以降とprogramPacketデータ length += 5; // 3 sdtのデータ length += 3; // x sdtServiceFieldの長さ for(SdtServiceField ssfield : serviceFields) { length += ssfield.getSize(); } // 4 crc32の長さ length += 4; // sdtServiceFieldの長さを調べます。 setSectionLength(length); } /** * {@inheritDoc} */ @Override public void analyze(IReadChannel ch) throws Exception { // 先頭の部分解析しておく。 analyzeHeader(ch); Bit8 originalNetworkId_1 = new Bit8(); Bit8 originalNetworkId_2 = new Bit8(); reservedFutureUse2 = new Bit8(); BitLoader bitLoader = new BitLoader(ch); bitLoader.load(originalNetworkId_1, originalNetworkId_2, reservedFutureUse2); originalNetworkId = (short)((originalNetworkId_1.get() << 8) | originalNetworkId_2.get()); // ループで読み込むべきサイズはsectionLength - 8 int size = getSectionLength() - 8; while(size > 4) { // まだデータがのこっていたらループで読み込みを実行する。 SdtServiceField ssfield = new SdtServiceField(); ssfield.analyze(ch); size -= ssfield.getSize(); serviceFields.add(ssfield); } return; } @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 List<Bit> getBits() { List<Bit> list = super.getBits(); list.add(new Bit8(originalNetworkId >>> 8)); list.add(new Bit8(originalNetworkId)); list.add(reservedFutureUse2); for(SdtServiceField ssfield : serviceFields) { list.addAll(ssfield.getBits()); } return list; } @Override public String toString() { StringBuilder data = new StringBuilder(); data.append("Sdt:"); data.append("\n").append(super.toString()); data.append(" oni:").append(Integer.toHexString(originalNetworkId)); data.append(" rfu2:").append(reservedFutureUse2); for(SdtServiceField ssfield : serviceFields) { data.append("\n"); data.append(ssfield); } return data.toString(); } }