NekoX/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java

262 lines
10 KiB
Java

/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2015.
*/
package org.telegram.messenger.video;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaFormat;
import com.coremedia.iso.boxes.AbstractMediaHeaderBox;
import com.coremedia.iso.boxes.SampleDescriptionBox;
import com.coremedia.iso.boxes.SoundMediaHeaderBox;
import com.coremedia.iso.boxes.VideoMediaHeaderBox;
import com.mp4parser.iso14496.part15.AvcConfigurationBox;
import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.AudioSpecificConfig;
import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.DecoderConfigDescriptor;
import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ESDescriptor;
import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.SLConfigDescriptor;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
@TargetApi(16)
public class Track {
private long trackId = 0;
private ArrayList<Sample> samples = new ArrayList<Sample>();
private long duration = 0;
private String handler;
private AbstractMediaHeaderBox headerBox = null;
private SampleDescriptionBox sampleDescriptionBox = null;
private LinkedList<Integer> syncSamples = null;
private int timeScale;
private Date creationTime = new Date();
private int height;
private int width;
private float volume = 0;
private ArrayList<Long> sampleDurations = new ArrayList<Long>();
private boolean isAudio = false;
private static Map<Integer, Integer> samplingFrequencyIndexMap = new HashMap<Integer, Integer>();
private long lastPresentationTimeUs = 0;
private boolean first = true;
static {
samplingFrequencyIndexMap.put(96000, 0x0);
samplingFrequencyIndexMap.put(88200, 0x1);
samplingFrequencyIndexMap.put(64000, 0x2);
samplingFrequencyIndexMap.put(48000, 0x3);
samplingFrequencyIndexMap.put(44100, 0x4);
samplingFrequencyIndexMap.put(32000, 0x5);
samplingFrequencyIndexMap.put(24000, 0x6);
samplingFrequencyIndexMap.put(22050, 0x7);
samplingFrequencyIndexMap.put(16000, 0x8);
samplingFrequencyIndexMap.put(12000, 0x9);
samplingFrequencyIndexMap.put(11025, 0xa);
samplingFrequencyIndexMap.put(8000, 0xb);
}
public Track(int id, MediaFormat format, boolean isAudio) throws Exception {
trackId = id;
if (!isAudio) {
sampleDurations.add((long)3015);
duration = 3015;
width = format.getInteger(MediaFormat.KEY_WIDTH);
height = format.getInteger(MediaFormat.KEY_HEIGHT);
timeScale = 90000;
syncSamples = new LinkedList<Integer>();
handler = "vide";
headerBox = new VideoMediaHeaderBox();
sampleDescriptionBox = new SampleDescriptionBox();
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.equals("video/avc")) {
VisualSampleEntry visualSampleEntry = new VisualSampleEntry("avc1");
visualSampleEntry.setDataReferenceIndex(1);
visualSampleEntry.setDepth(24);
visualSampleEntry.setFrameCount(1);
visualSampleEntry.setHorizresolution(72);
visualSampleEntry.setVertresolution(72);
visualSampleEntry.setWidth(width);
visualSampleEntry.setHeight(height);
AvcConfigurationBox avcConfigurationBox = new AvcConfigurationBox();
if (format.getByteBuffer("csd-0") != null) {
ArrayList<byte[]> spsArray = new ArrayList<byte[]>();
ByteBuffer spsBuff = format.getByteBuffer("csd-0");
spsBuff.position(4);
byte[] spsBytes = new byte[spsBuff.remaining()];
spsBuff.get(spsBytes);
spsArray.add(spsBytes);
ArrayList<byte[]> ppsArray = new ArrayList<byte[]>();
ByteBuffer ppsBuff = format.getByteBuffer("csd-1");
ppsBuff.position(4);
byte[] ppsBytes = new byte[ppsBuff.remaining()];
ppsBuff.get(ppsBytes);
ppsArray.add(ppsBytes);
avcConfigurationBox.setSequenceParameterSets(spsArray);
avcConfigurationBox.setPictureParameterSets(ppsArray);
}
avcConfigurationBox.setAvcLevelIndication(13);
avcConfigurationBox.setAvcProfileIndication(100);
avcConfigurationBox.setBitDepthLumaMinus8(-1);
avcConfigurationBox.setBitDepthChromaMinus8(-1);
avcConfigurationBox.setChromaFormat(-1);
avcConfigurationBox.setConfigurationVersion(1);
avcConfigurationBox.setLengthSizeMinusOne(3);
avcConfigurationBox.setProfileCompatibility(0);
visualSampleEntry.addBox(avcConfigurationBox);
sampleDescriptionBox.addBox(visualSampleEntry);
} else if (mime.equals("video/mp4v")) {
VisualSampleEntry visualSampleEntry = new VisualSampleEntry("mp4v");
visualSampleEntry.setDataReferenceIndex(1);
visualSampleEntry.setDepth(24);
visualSampleEntry.setFrameCount(1);
visualSampleEntry.setHorizresolution(72);
visualSampleEntry.setVertresolution(72);
visualSampleEntry.setWidth(width);
visualSampleEntry.setHeight(height);
sampleDescriptionBox.addBox(visualSampleEntry);
}
} else {
sampleDurations.add((long)1024);
duration = 1024;
isAudio = true;
volume = 1;
timeScale = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
handler = "soun";
headerBox = new SoundMediaHeaderBox();
sampleDescriptionBox = new SampleDescriptionBox();
AudioSampleEntry audioSampleEntry = new AudioSampleEntry("mp4a");
audioSampleEntry.setChannelCount(format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
audioSampleEntry.setSampleRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
audioSampleEntry.setDataReferenceIndex(1);
audioSampleEntry.setSampleSize(16);
ESDescriptorBox esds = new ESDescriptorBox();
ESDescriptor descriptor = new ESDescriptor();
descriptor.setEsId(0);
SLConfigDescriptor slConfigDescriptor = new SLConfigDescriptor();
slConfigDescriptor.setPredefined(2);
descriptor.setSlConfigDescriptor(slConfigDescriptor);
DecoderConfigDescriptor decoderConfigDescriptor = new DecoderConfigDescriptor();
decoderConfigDescriptor.setObjectTypeIndication(0x40);
decoderConfigDescriptor.setStreamType(5);
decoderConfigDescriptor.setBufferSizeDB(1536);
decoderConfigDescriptor.setMaxBitRate(96000);
decoderConfigDescriptor.setAvgBitRate(96000);
AudioSpecificConfig audioSpecificConfig = new AudioSpecificConfig();
audioSpecificConfig.setAudioObjectType(2);
audioSpecificConfig.setSamplingFrequencyIndex(samplingFrequencyIndexMap.get((int)audioSampleEntry.getSampleRate()));
audioSpecificConfig.setChannelConfiguration(audioSampleEntry.getChannelCount());
decoderConfigDescriptor.setAudioSpecificInfo(audioSpecificConfig);
descriptor.setDecoderConfigDescriptor(decoderConfigDescriptor);
ByteBuffer data = descriptor.serialize();
esds.setEsDescriptor(descriptor);
esds.setData(data);
audioSampleEntry.addBox(esds);
sampleDescriptionBox.addBox(audioSampleEntry);
}
}
public long getTrackId() {
return trackId;
}
public void addSample(long offset, MediaCodec.BufferInfo bufferInfo) {
boolean isSyncFrame = !isAudio && (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
samples.add(new Sample(offset, bufferInfo.size));
if (syncSamples != null && isSyncFrame) {
syncSamples.add(samples.size());
}
long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs;
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
delta = (delta * timeScale + 500000L) / 1000000L;
if (!first) {
sampleDurations.add(sampleDurations.size() - 1, delta);
duration += delta;
}
first = false;
}
public ArrayList<Sample> getSamples() {
return samples;
}
public long getDuration() {
return duration;
}
public String getHandler() {
return handler;
}
public AbstractMediaHeaderBox getMediaHeaderBox() {
return headerBox;
}
public SampleDescriptionBox getSampleDescriptionBox() {
return sampleDescriptionBox;
}
public long[] getSyncSamples() {
if (syncSamples == null || syncSamples.isEmpty()) {
return null;
}
long[] returns = new long[syncSamples.size()];
for (int i = 0; i < syncSamples.size(); i++) {
returns[i] = syncSamples.get(i);
}
return returns;
}
public int getTimeScale() {
return timeScale;
}
public Date getCreationTime() {
return creationTime;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float getVolume() {
return volume;
}
public ArrayList<Long> getSampleDurations() {
return sampleDurations;
}
public boolean isAudio() {
return isAudio;
}
}