
org.libav.DefaultMediaReader Maven / Gradle / Ivy
/*
* Copyright (C) 2012 Ondrej Perutka
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
package org.libav;
import java.util.*;
import org.libav.avcodec.ICodecContextWrapper;
import org.libav.avcodec.IPacketWrapper;
import org.libav.avformat.FormatContextWrapperFactory;
import org.libav.avformat.IFormatContextWrapper;
import org.libav.avformat.IIOContextWrapper;
import org.libav.avformat.IStreamWrapper;
import org.libav.avutil.bridge.AVMediaType;
import org.libav.data.BufferedPacketReader;
import org.libav.data.IPacketConsumer;
import org.libav.util.Buffer;
import org.libav.util.Rational;
/**
* Default implementation of the media reader interface.
*
* @author Ondrej Perutka
*/
public class DefaultMediaReader implements IMediaReader {
private IFormatContextWrapper formatContext;
private BufferedPacketReader packetReader;
private List> streamBuffers;
private boolean[] bufferingEnabled;
private IStreamWrapper[] streams;
private int[] vStreams;
private int[] aStreams;
private List> packetConsumers;
private Rational[] timeBases;
private long position;
/**
* Open the given media URL using the default media reader.
*
* @param url a media URL
* @throws LibavException if an error occurs while opening the media
*/
public DefaultMediaReader(String url) throws LibavException {
formatContext = FormatContextWrapperFactory.getInstance().openMedia(url);
packetReader = new BufferedPacketReader(formatContext, 100);
formatContext.findStreamInfo();
streams = formatContext.getStreams();
ICodecContextWrapper[] ccs = new ICodecContextWrapper[streams.length];
streamBuffers = new ArrayList>();
bufferingEnabled = new boolean[streams.length];
packetConsumers = new ArrayList>();
timeBases = new Rational[streams.length];
int v = 0, a = 0;
for (int i = 0; i < streams.length; i++) {
ccs[i] = streams[i].getCodecContext();
streamBuffers.add(new Buffer(20));
bufferingEnabled[i] = false;
packetConsumers.add(Collections.synchronizedSet(new HashSet()));
switch (ccs[i].getCodecType()) {
case AVMediaType.AVMEDIA_TYPE_VIDEO: v++; break;
case AVMediaType.AVMEDIA_TYPE_AUDIO: a++; break;
default: break;
}
timeBases[i] = streams[i].getTimeBase().mul(1000);
}
vStreams = new int[v];
aStreams = new int[a];
v = a = 0;
for (int i = 0; i < streams.length; i++) {
switch (ccs[i].getCodecType()) {
case AVMediaType.AVMEDIA_TYPE_VIDEO: vStreams[v++] = i; break;
case AVMediaType.AVMEDIA_TYPE_AUDIO: aStreams[a++] = i; break;
default: break;
}
}
position = 0;
}
@Override
public IFormatContextWrapper getFormatContext() {
return formatContext;
}
@Override
public int getStreamCount() {
return streams.length;
}
@Override
public void addPacketConsumer(int streamIndex, IPacketConsumer consumer) {
packetConsumers.get(streamIndex).add(consumer);
}
@Override
public void removePacketConsumer(int streamIndex, IPacketConsumer consumer) {
packetConsumers.get(streamIndex).remove(consumer);
}
@Override
public boolean containsPacketConsumer(int streamIndex, IPacketConsumer consumer) {
return packetConsumers.get(streamIndex).contains(consumer);
}
@Override
public IStreamWrapper getStream(int streamIndex) {
return streams[streamIndex];
}
@Override
public int getVideoStreamCount() {
return vStreams.length;
}
@Override
public IStreamWrapper getVideoStream(int videoStreamIndex) {
return streams[vStreams[videoStreamIndex]];
}
@Override
public void addVideoPacketConsumer(int videoStreamIndex, IPacketConsumer consumer) {
addPacketConsumer(vStreams[videoStreamIndex], consumer);
}
@Override
public void removeVideoPacketConsumer(int videoStreamIndex, IPacketConsumer consumer) {
removePacketConsumer(vStreams[videoStreamIndex], consumer);
}
@Override
public boolean containsVideoPacketConsumer(int videoStreamIndex, IPacketConsumer consumer) {
return containsPacketConsumer(vStreams[videoStreamIndex], consumer);
}
@Override
public int getAudioStreamCount() {
return aStreams.length;
}
@Override
public IStreamWrapper getAudioStream(int audioStremIndex) {
return streams[aStreams[audioStremIndex]];
}
@Override
public void addAudioPacketConsumer(int audioStreamIndex, IPacketConsumer consumer) {
addPacketConsumer(aStreams[audioStreamIndex], consumer);
}
@Override
public void removeAudioPacketConsumer(int audioStreamIndex, IPacketConsumer consumer) {
removePacketConsumer(aStreams[audioStreamIndex], consumer);
}
@Override
public boolean containsAudioPacketConsumer(int audioStreamIndex, IPacketConsumer consumer) {
return containsPacketConsumer(aStreams[audioStreamIndex], consumer);
}
@Override
public long getDuration() {
return formatContext.getDuration();
}
@Override
public long getStreamDuration(int streamIndex) {
IStreamWrapper stream = getStream(streamIndex);
Rational tb = stream.getTimeBase();
return tb.mul(1000).mul(stream.getDuration()).longValue();
}
@Override
public long getAudioStreamDuration(int audioStreamIndex) {
return getStreamDuration(aStreams[audioStreamIndex]);
}
@Override
public long getVideoStreamDuration(int videoStreamIndex) {
return getStreamDuration(vStreams[videoStreamIndex]);
}
@Override
public long getPosition() {
return position;
}
@Override
public boolean isSeekable() {
if (isClosed())
return false;
IIOContextWrapper ioc = formatContext.getIOContext();
return ioc == null ? false : ioc.isSeekable();
}
@Override
public synchronized void seek(long time) throws LibavException {
if (isClosed())
return;
dropAllBuffers();
packetReader.resetEof();
formatContext.seekFile(time - 10000, time, time + 500);
position = time;
}
@Override
public synchronized void dropAllBuffers() {
packetReader.dropBuffer();
for (Buffer sb : streamBuffers) {
while (sb.getItemCount() > 0)
sb.get().free();
}
}
@Override
public boolean readNextPacket() throws LibavException {
IPacketWrapper pw;
synchronized (this) {
if (isClosed())
return false;
pw = packetReader.nextPacket();
}
if (pw != null)
sendPacket(pw);
return pw != null;
}
@Override
public boolean readNextPacket(int streamIndex) throws LibavException {
IPacketWrapper pw;
synchronized (this) {
if (isClosed())
return false;
setStreamBufferingEnabled(streamIndex, true);
if (streamBuffers.get(streamIndex).getItemCount() > 0)
pw = streamBuffers.get(streamIndex).get();
else {
pw = packetReader.nextPacket();
if (pw == null)
return false;
else if (pw.getStreamIndex() != streamIndex && isStreamBufferingEnabled(pw.getStreamIndex()))
streamBuffers.get(pw.getStreamIndex()).put(pw);
}
}
if (pw.getStreamIndex() == streamIndex)
sendPacket(pw);
return true;
}
@Override
public boolean readNextVideoPacket(int videoStreamIndex) throws LibavException {
return readNextPacket(vStreams[videoStreamIndex]);
}
@Override
public boolean readNextAudioPacket(int audioStreamIndex) throws LibavException {
return readNextPacket(aStreams[audioStreamIndex]);
}
@Override
public boolean isStreamBufferingEnabled(int streamIndex) {
return bufferingEnabled[streamIndex];
}
@Override
public void setStreamBufferingEnabled(int streamIndex, boolean enabled) {
synchronized (this) {
bufferingEnabled[streamIndex] = enabled;
if (!enabled) {
Buffer buf = streamBuffers.get(streamIndex);
while (buf.getItemCount() > 0)
buf.get().free();
}
}
}
@Override
public boolean isAudioStreamBufferingEnabled(int audioStreamIndex) {
return isStreamBufferingEnabled(aStreams[audioStreamIndex]);
}
@Override
public void setAudioStreamBufferingEnabled(int audioStreamIndex, boolean enabled) {
setStreamBufferingEnabled(aStreams[audioStreamIndex], enabled);
}
@Override
public boolean isVideoStreamBufferingEnabled(int videoStreamIndex) {
return isStreamBufferingEnabled(vStreams[videoStreamIndex]);
}
@Override
public void setVideoStreamBufferingEnabled(int videoStreamIndex, boolean enabled) {
setStreamBufferingEnabled(vStreams[videoStreamIndex], enabled);
}
@Override
public void close() throws LibavException {
synchronized (this) {
for (Buffer sb : streamBuffers) {
while (sb.getItemCount() > 0)
sb.get().free();
}
packetReader.close();
if (formatContext != null)
formatContext.close();
formatContext = null;
}
}
@Override
public boolean isClosed() {
return formatContext == null;
}
private void sendPacket(IPacketWrapper packet) throws LibavException {
Set pc = packetConsumers.get(packet.getStreamIndex());
IPacketWrapper pw;
if (packet.getDts() > 0)
position = timeBases[packet.getStreamIndex()].mul(packet.getDts()).longValue();
synchronized (pc) {
for (IPacketConsumer c : pc) {
pw = packet.clone();
c.processPacket(this, pw);
pw.free();
}
}
packet.free();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy