/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.media.mp4.atom.stsd.data; import java.nio.ByteBuffer; import com.ttProject.util.BufferUtil; import com.ttProject.media.mp4.Atom; import com.ttProject.media.mp4.IAtomAnalyzer; import com.ttProject.nio.channels.IReadChannel; /** * mp4のstsdの内部データのさらに奥のデータ * 音声用らしい * こちらはaacのmediaSequenceHeaderを保持しているが、解析する必要あり。 * データ的には音声onlyではないかもしれない * @author taktod */ @SuppressWarnings("unused") public class Esds extends Atom { private int unknown; // 内部のタグのデータ private final int ES_TAG = 0x03; private final int DECODER_CONFIG = 0x04; private final int DECODER_SPECIFIC = 0x05; private final int SL_CONFIG = 0x06; private byte objectType; private byte[] sequenceHeader; public byte[] getSequenceHeader() { return sequenceHeader; } /** * esdsに設定されているobjectTypeのyteデータを参照する。 * TODO このデータを見れば、コーデックがmp3かaacかとかわかるはず。 * @return */ public byte getObjectType() { return objectType; } public Esds(int position, int size) { super(Esds.class.getSimpleName().toLowerCase(), position, size); } @Override public void analyze(IReadChannel ch, IAtomAnalyzer analyzer) throws Exception { // とりあえず解析しよう。 ch.position(getPosition() + 8); ByteBuffer buffer = BufferUtil.safeRead(ch, getSize() - 8); unknown = buffer.getInt(); while(buffer.remaining() > 0) { analyzeTag(buffer); } } private void analyzeTag(ByteBuffer buffer) throws Exception { if(buffer.remaining() == 0) { return; } // tagを調べる。 byte tag = buffer.get(); int size = getSize(buffer); byte flags; switch(tag) { case ES_TAG: // 次のデータが可変長変数値 // 次の2バイトはES_ID short esId = buffer.getShort(); flags = buffer.get(); if(flags != 0) { // ここでよくわからんエラーでた・・・どういうことだ? throw new Exception("ES_TAG flags is unknown."); } // ここで元の場所に戻る。 analyzeTag(buffer); break; case DECODER_CONFIG: // 1バイトオブジェクトタイプ objectType = buffer.get(); switch(objectType & 0xFF) { case 0x01: // system v1 break; case 0x02: // system v2 break; case 0x20: // mpeg4-video break; case 0x21: // mpeg-4 avc sps break; case 0x22: // mpeg-4 avc pps break; case 0x40: // mpeg-4 audio(aac?) break; case 0x60: // mpeg-2 simple video break; case 0x61: // mpeg-2 main video break; case 0x62: // mpeg-2 snr video break; case 0x63: // mpeg-2 special video break; case 0x64: // mpeg-2 high video break; case 0x65: // mpeg-2 4:2:2 video break; case 0x66: // mpeg-4 adts main break; case 0x67: // mpeg-4 adts low complexity break; case 0x68: // mpeg-4 adts scalable sampling rate break; case 0x69: // mpeg-2 adts break; case 0x6A: // mpeg-1 video break; case 0x6B: // mpeg-1 adts break; case 0x6C: // jpeg video break; case 0xC0: // private audio break; case 0xD0: // private video break; case 0xE0: // 16-bit PCM le audio break; case 0xE1: // vorbis audio break; case 0xE2: // dolby v3 ac3 audio break; case 0xE3: // alaw audio break; case 0xE4: // mulaw audio break; case 0xE5: // adpcm audio break; case 0xE6: // 16-bit pcm big endian audio break; case 0xF0: // Y'CbCr 4:2:0(YV12 video) break; case 0xF1: // H264 video break; case 0xF2: // H263 video break; case 0xF3: // H261 video break; default: // unknwon break; } // 次の1バイト flags int data = buffer.getInt(); flags = (byte)((data >> 24) & 0xFF); int bufferSize = (data & 0x00FFFFFF); int maxBitRate = buffer.getInt(); int avgBitRate = buffer.getInt(); // ここで元の場所に戻る。 analyzeTag(buffer); break; case DECODER_SPECIFIC: // サイズを取得してそのサイズ分がMediaSequenceHeaderの情報になる。(aacの場合) byte[] msh = new byte[size]; buffer.get(msh); // このデータがmediaSequenceHeaderのデータ(flvにするにはこれが欲しい) sequenceHeader = msh; analyzeTag(buffer); break; case SL_CONFIG: byte[] conf = new byte[size]; buffer.get(conf); break; } } private int getSize(ByteBuffer buffer) { int size = 0; byte b = 0; do { b = buffer.get(); size = size * 0x80 + (b & 0x7F); }while((b & 0x80) != 0x00); return size; } }