All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.libav.video.VideoFrameDecoder 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.video;

import com.sun.jna.Pointer;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.libav.IDecoder;
import org.libav.LibavException;
import org.libav.avcodec.*;
import org.libav.avformat.IStreamWrapper;
import org.libav.avutil.bridge.AVMediaType;
import org.libav.avutil.bridge.IAVUtilLibrary;
import org.libav.data.IFrameConsumer;
import org.libav.util.Rational;

/**
 * Video frame decoder.
 * 
 * @author Ondrej Perutka
 */
public class VideoFrameDecoder implements IDecoder {
    
    private IStreamWrapper stream;
    private ICodecContextWrapper cc;
    
    private Rational sTimeBase;
    private long pts;
    private long frameDuration;
    
    private IFrameWrapper frame;
    
    private final Set consumers;

    /**
     * Create a new video frame decoder for the given video stream.
     * 
     * @param stream a video stream
     * @throws LibavException if the decoder cannot be created for some reason
     * (caused by the Libav)
     */
    public VideoFrameDecoder(IStreamWrapper stream) throws LibavException {
        this.stream = stream;
        
        cc = stream.getCodecContext();
        cc.clearWrapperCache();
        if (cc.getCodecType() != AVMediaType.AVMEDIA_TYPE_VIDEO)
            throw new IllegalArgumentException("not a video stream");
        
        cc.open(CodecWrapperFactory.getInstance().findDecoder(cc.getCodecId()));
        
        sTimeBase = stream.getTimeBase().mul(1000);
        pts = 0;
        frameDuration = cc.getTimeBase().mul(1000).longValue();

        frame = FrameWrapperFactory.getInstance().allocFrame();

        consumers = Collections.synchronizedSet(new HashSet());
    }
    
    @Override
    public ICodecContextWrapper getCodecContext() {
        return cc;
    }

    @Override
    public IStreamWrapper getStream() {
        return stream;
    }

    @Override
    public synchronized void close() {
        if (frame != null)
            frame.free();
        cc.close();
    }
    
    @Override
    public boolean isClosed() {
        return cc.isClosed();
    }

    @Override
    public synchronized void processPacket(Object producer, IPacketWrapper packet) throws LibavException {
        if (isClosed() || packet.getStreamIndex() != stream.getIndex())
            return;
        
        //System.out.printf("VP: dts = %d\n", sTimeBase.mul(packet.getDts()).longValue());
        Pointer tmp = packet.getData();
        while (packet.getSize() > 0) {
            if (cc.decodeVideoFrame(packet, frame))
                sendFrame(transformPts(frame));
        }
        packet.setData(tmp);

        packet.free();
    }
    
    @Override
    public synchronized void flush() throws LibavException {
        IFrameWrapper fr;
        while ((fr = flushContext()) != null)
            sendFrame(transformPts(fr));
    }
    
    private synchronized IFrameWrapper flushContext() throws LibavException {
        if (isClosed())
            return null;
        
        IPacketWrapper packet = PacketWrapperFactory.getInstance().alloc();
        IFrameWrapper result = null;
        
        packet.setSize(0);
        packet.setData(null);
        if (cc.decodeVideoFrame(packet, frame))
            result = frame;
        packet.free();
        
        return result;
    }
    
    
    protected void sendFrame(IFrameWrapper frame) throws LibavException {
        synchronized (consumers) {
            for (IFrameConsumer c : consumers)
                c.processFrame(this, frame);
        }
    }
    
    private IFrameWrapper transformPts(IFrameWrapper frame) {
        //System.out.printf("decoded frame: pts = %d, packet_pts = %d, packet_dts = %d, sTimeBase = %s\n", frame.getPts(), frame.getPacketPts(), frame.getPacketDts(), sTimeBase.toString());
        if (frame.getPacketDts() != IAVUtilLibrary.AV_NOPTS_VALUE)
            frame.setPts(sTimeBase.mul(frame.getPacketDts()).longValue());
        else {
            frame.setPts(pts);
            pts += frameDuration;
        }
        
        return frame;
    }

    @Override
    public void addFrameConsumer(IFrameConsumer c) {
        consumers.add(c);
    }

    @Override
    public void removeFrameConsumer(IFrameConsumer c) {
        consumers.remove(c);
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy