/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.container.mpegts.type; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import com.ttProject.container.mpegts.ProgramPacket; import com.ttProject.container.mpegts.descriptor.Descriptor; import com.ttProject.container.mpegts.descriptor.ServiceDescriptor; import com.ttProject.container.mpegts.field.SdtServiceField; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.nio.channels.IReadChannel; import com.ttProject.unit.extra.BitConnector; import com.ttProject.unit.extra.BitLoader; import com.ttProject.unit.extra.bit.Bit1; import com.ttProject.unit.extra.bit.Bit13; import com.ttProject.unit.extra.bit.Bit16; import com.ttProject.unit.extra.bit.Bit2; import com.ttProject.unit.extra.bit.Bit32; import com.ttProject.unit.extra.bit.Bit4; import com.ttProject.unit.extra.bit.Bit8; import com.ttProject.util.BufferUtil; /** * Sdt(Service Description Table) * sample. * 474011100042F0240001C100000001FF 0001FC8013481101054C696261760953657276696365303168C5DB49 * 47 40 11 10 mpegtsPacketHeader * 00 42 F0 24 00 01 C1 00 00 programPacket * 00 01 FF sdt * 00 01 FC 80 13 sdtServiceField * 48 11 descriptor * 01 05 [4C 69 62 61 76] 09 [53 65 72 76 69 63 65 30 31] ServiceDescriptor * 68 C5 DB 49 crc32 * @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 { /** logger */ @SuppressWarnings("unused") private Logger logger = Logger.getLogger(Sdt.class); private Bit16 originalNetworkId = null; private Bit8 reservedFutureUse2 = null; private List<SdtServiceField> serviceFields = new ArrayList<SdtServiceField>(); private Bit32 crc32 = new Bit32(); /** * constructor * @param syncByte * @param transportErrorIndicator * @param payloadUnitStartIndicator * @param transportPriority * @param pid * @param scramblingControl * @param adaptationFieldExist * @param payloadFieldExist * @param continuityCounter */ public Sdt(Bit8 syncByte, Bit1 transportErrorIndicator, Bit1 payloadUnitStartIndicator, Bit1 transportPriority, Bit13 pid, Bit2 scramblingControl, Bit1 adaptationFieldExist, Bit1 payloadFieldExist, Bit4 continuityCounter) { super(syncByte, transportErrorIndicator, payloadUnitStartIndicator, transportPriority, pid, scramblingControl, adaptationFieldExist, payloadFieldExist, continuityCounter); super.update(); } /** * constructor */ public Sdt() { this(new Bit8(0x47), new Bit1(), new Bit1(1), new Bit1(), new Bit13(0x11), new Bit2(), new Bit1(), new Bit1(1), new Bit4()); // need to load here. try { super.load(new ByteReadChannel(new byte[]{ 0x00, 0x42, (byte)0xF0, 0x24, 0x00, 0x01, (byte)0xC1, 0x00, 0x00, })); originalNetworkId = new Bit16(1); reservedFutureUse2 = new Bit8(0xFF); } catch(Exception e) { } super.update(); } /** * {@inheritDoc} */ @Override public void minimumLoad(IReadChannel channel) throws Exception { super.minimumLoad(channel); BitLoader loader = new BitLoader(channel); loader.load(crc32); super.update(); } /** * {@inheritDoc} */ @Override public void load(IReadChannel channel) throws Exception { if(isLoaded()) { return; } IReadChannel holdChannel = new ByteReadChannel(getBuffer()); super.load(holdChannel); BitLoader loader = new BitLoader(holdChannel); originalNetworkId = new Bit16(); reservedFutureUse2 = new Bit8(); loader.load(originalNetworkId, reservedFutureUse2); int size = getSectionLength() - 8 - 4; while(size > 0) { SdtServiceField ssfield = new SdtServiceField(); ssfield.load(holdChannel); size -= ssfield.getSize(); serviceFields.add(ssfield); } super.update(); } /** * {@inheritDoc} */ @Override protected void requestUpdate() throws Exception { BitConnector connector = new BitConnector(); connector.feed(originalNetworkId, reservedFutureUse2); for(SdtServiceField ssField : serviceFields) { connector.feed(ssField.getBits()); } ByteBuffer tmpBuffer = BufferUtil.connect( getHeaderBuffer(), connector.connect() ); // crc32 is required. int crc32 = calculateCrc(tmpBuffer); this.crc32.set(crc32); ByteBuffer buffer = ByteBuffer.allocate(188); buffer.put(tmpBuffer); buffer.putInt(crc32); // fill til 188 bytes while(buffer.position() < 188) { buffer.put((byte)0xFF); } buffer.flip(); super.setData(buffer); } /** * write default provider. * @param provider * @param name */ public void writeDefaultProvider(String provider, String name) { // check other service field. SdtServiceField targetField = null; for(SdtServiceField ssField : serviceFields) { if(ssField.getServiceId() == 1) { targetField = ssField; break; } } // if none, add if(targetField == null) { targetField = new SdtServiceField(); serviceFields.add(targetField); } // check descriptor ServiceDescriptor targetDescriptor = null; for(Descriptor descriptor : targetField.getDescriptors()) { if(descriptor instanceof ServiceDescriptor) { targetDescriptor = (ServiceDescriptor)descriptor; break; } } // if none, add. if(targetDescriptor == null) { targetDescriptor = new ServiceDescriptor(targetField); targetField.addDescriptor(targetDescriptor); } targetDescriptor.setName(provider, name); // update length short length = 0; // sectionlength ... and programPacket length += 5; // sdt length += 3; // sdtServiceField for(SdtServiceField ssField : serviceFields) { length += ssField.getSize(); } // crc32 length += 4; setSectionLength(length); // update flag. super.update(); } /** * {@inheritDoc} */ @Override public int getCrc() { return crc32.get(); } }