基于javasockets的网络视频流

基于javasockets的网络视频流,java,sockets,streaming,server,rtsp,Java,Sockets,Streaming,Server,Rtsp,我正在开发一个网络java应用程序。我想从网络上传输视频(可能使用套接字)。我在互联网上搜索,但我没有找到任何工作的服务器和客户端代码来将视频从服务器传输到客户端。 任何人都可以找到流媒体服务器和客户端,或者编写一个简单的程序,以便我了解如何使用java完成流媒体 另外,我在网上找到了一份与此相关的作业。但它存在误差,有些方法也没有实现。如果您可以删除错误并完成这些方法,这也会很有帮助。。 Xuggle是/曾经是最好的: 现在我不知道;我没有一个完整的项目,但我相信它有一个演示文件的例子 用X

我正在开发一个网络java应用程序。我想从网络上传输视频(可能使用套接字)。我在互联网上搜索,但我没有找到任何工作的服务器和客户端代码来将视频从服务器传输到客户端。 任何人都可以找到流媒体服务器和客户端,或者编写一个简单的程序,以便我了解如何使用java完成流媒体

另外,我在网上找到了一份与此相关的作业。但它存在误差,有些方法也没有实现。如果您可以删除错误并完成这些方法,这也会很有帮助。。
Xuggle是/曾经是最好的:

现在我不知道;我没有一个完整的项目,但我相信它有一个演示文件的例子

用Xuggler在谷歌搜索xuggle视频流演示或类似关键字。它易于使用并支持大多数已知格式,因为它本身包装了FFMPEG。

以下是基本代码:

但我把它改成:

package Pasban;

/**
 *
 * @modified by Pasban
 */
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

import com.xuggle.xuggler.Global;
import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IPacket;
import com.xuggle.xuggler.IPixelFormat;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IVideoPicture;
import com.xuggle.xuggler.IVideoResampler;
import com.xuggle.xuggler.Utils;
import com.xuggle.xuggler.demos.VideoImage;
import java.awt.Dimension;

/**
 * Takes a media container, finds the first video stream,
 * decodes that stream, and then plays the audio and video.
 *
 * This code does a VERY coarse job of matching time-stamps, and thus
 * the audio and video will float in and out of slight sync.  Getting
 * time-stamps syncing-up with audio is very system dependent and left
 * as an exercise for the reader.
 * 
 * @author aclarke
 *
 */
public class DecodeAndPlayAudioAndVideo {

    /**
     * The audio line we'll output sound to; it'll be the default audio device on your system if available
     */
    private static SourceDataLine mLine;
    /**
     * The window we'll draw the video on.
     * 
     */
    private static VideoImage mScreen = null;
    private static long mSystemVideoClockStartTime;
    private static long mFirstVideoTimestampInStream;

    /**
     * Takes a media container (file) as the first argument, opens it,
     * plays audio as quickly as it can, and opens up a Swing window and displays
     * video frames with <i>roughly</i> the right timing.
     *  
     * @param args Must contain one string which represents a filename
     */
    @SuppressWarnings("deprecation")
    public static void main(String[] args) {

        String filename = "http://techslides.com/demos/sample-videos/small.mp4";

        // Let's make sure that we can actually convert video pixel formats.
        if (!IVideoResampler.isSupported(IVideoResampler.Feature.FEATURE_COLORSPACECONVERSION)) {
            throw new RuntimeException("you must install the GPL version of Xuggler (with IVideoResampler support) for this demo to work");
        }

        // Create a Xuggler container object
        IContainer container = IContainer.make();

        // Open up the container
        if (container.open("http://techslides.com/demos/sample-videos/small.mp4", IContainer.Type.READ, null) < 0) {
            throw new IllegalArgumentException("could not open file: " + filename);
        }

        // query how many streams the call to open found
        int numStreams = container.getNumStreams();

        // and iterate through the streams to find the first audio stream
        int videoStreamId = -1;
        IStreamCoder videoCoder = null;
        int audioStreamId = -1;
        IStreamCoder audioCoder = null;
        for (int i = 0; i < numStreams; i++) {
            // Find the stream object
            IStream stream = container.getStream(i);
            // Get the pre-configured decoder that can decode this stream;
            IStreamCoder coder = stream.getStreamCoder();

            if (videoStreamId == -1 && coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
                videoStreamId = i;
                videoCoder = coder;
            } else if (audioStreamId == -1 && coder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {
                audioStreamId = i;
                audioCoder = coder;
            }
        }
        if (videoStreamId == -1 && audioStreamId == -1) {
            throw new RuntimeException("could not find audio or video stream in container: " + filename);
        }

        /*
         * Check if we have a video stream in this file.  If so let's open up our decoder so it can
         * do work.
         */
        IVideoResampler resampler = null;
        if (videoCoder != null) {
            if (videoCoder.open() < 0) {
                throw new RuntimeException("could not open audio decoder for container: " + filename);
            }

            if (videoCoder.getPixelType() != IPixelFormat.Type.BGR24) {
                // if this stream is not in BGR24, we're going to need to
                // convert it.  The VideoResampler does that for us.
                resampler = IVideoResampler.make(videoCoder.getWidth(), videoCoder.getHeight(), IPixelFormat.Type.BGR24,
                        videoCoder.getWidth(), videoCoder.getHeight(), videoCoder.getPixelType());

                openJavaVideo(videoCoder);


                if (resampler == null) {
                    throw new RuntimeException("could not create color space resampler for: " + filename);
                }
            }
            /*
             * And once we have that, we draw a window on screen
             */
        }

        if (audioCoder != null) {
            if (audioCoder.open() < 0) {
                throw new RuntimeException("could not open audio decoder for container: " + filename);
            }

            /*
             * And once we have that, we ask the Java Sound System to get itself ready.
             */
            try {
                openJavaSound(audioCoder);
            } catch (LineUnavailableException ex) {
                throw new RuntimeException("unable to open sound device on your system when playing back container: " + filename);
            }
        }


        /*
         * Now, we start walking through the container looking at each packet.
         */
        IPacket packet = IPacket.make();
        mFirstVideoTimestampInStream = Global.NO_PTS;
        mSystemVideoClockStartTime = 0;
        while (container.readNextPacket(packet) >= 0) {
            /*
             * Now we have a packet, let's see if it belongs to our video stream
             */
            if (packet.getStreamIndex() == videoStreamId) {
                /*
                 * We allocate a new picture to get the data out of Xuggler
                 */
                IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(),
                        videoCoder.getWidth(), videoCoder.getHeight());

                /*
                 * Now, we decode the video, checking for any errors.
                 * 
                 */
                int bytesDecoded = videoCoder.decodeVideo(picture, packet, 0);
                if (bytesDecoded < 0) {
                    throw new RuntimeException("got error decoding audio in: " + filename);
                }

                /*
                 * Some decoders will consume data in a packet, but will not be able to construct
                 * a full video picture yet.  Therefore you should always check if you
                 * got a complete picture from the decoder
                 */
                if (picture.isComplete()) {
                    IVideoPicture newPic = picture;
                    /*
                     * If the resampler is not null, that means we didn't get the video in BGR24 format and
                     * need to convert it into BGR24 format.
                     */
                    if (resampler != null) {
                        // we must resample
                        newPic = IVideoPicture.make(resampler.getOutputPixelFormat(), picture.getWidth(), picture.getHeight());
                        if (resampler.resample(newPic, picture) < 0) {
                            throw new RuntimeException("could not resample video from: " + filename);
                        }
                    }
                    if (newPic.getPixelType() != IPixelFormat.Type.BGR24) {
                        throw new RuntimeException("could not decode video as BGR 24 bit data in: " + filename);
                    }

                    long delay = millisecondsUntilTimeToDisplay(newPic);
                    // if there is no audio stream; go ahead and hold up the main thread.  We'll end
                    // up caching fewer video pictures in memory that way.
                    try {
                        if (delay > 0) {
                            Thread.sleep(delay);
                        }
                    } catch (InterruptedException e) {
                        return;
                    }

                    // And finally, convert the picture to an image and display it

                    mScreen.setImage(Utils.videoPictureToImage(newPic));
                }
            } else if (packet.getStreamIndex() == audioStreamId) {
                /*
                 * We allocate a set of samples with the same number of channels as the
                 * coder tells us is in this buffer.
                 * 
                 * We also pass in a buffer size (1024 in our example), although Xuggler
                 * will probably allocate more space than just the 1024 (it's not important why).
                 */
                IAudioSamples samples = IAudioSamples.make(1024, audioCoder.getChannels());

                /*
                 * A packet can actually contain multiple sets of samples (or frames of samples
                 * in audio-decoding speak).  So, we may need to call decode audio multiple
                 * times at different offsets in the packet's data.  We capture that here.
                 */
                int offset = 0;

                /*
                 * Keep going until we've processed all data
                 */
                while (offset < packet.getSize()) {
                    int bytesDecoded = audioCoder.decodeAudio(samples, packet, offset);
                    if (bytesDecoded < 0) {
                        throw new RuntimeException("got error decoding audio in: " + filename);
                    }
                    offset += bytesDecoded;
                    /*
                     * Some decoder will consume data in a packet, but will not be able to construct
                     * a full set of samples yet.  Therefore you should always check if you
                     * got a complete set of samples from the decoder
                     */
                    if (samples.isComplete()) {
                        // note: this call will block if Java's sound buffers fill up, and we're
                        // okay with that.  That's why we have the video "sleeping" occur
                        // on another thread.
                        playJavaSound(samples);
                    }
                }
            } else {
                /*
                 * This packet isn't part of our video stream, so we just silently drop it.
                 */
                do {
                } while (false);
            }

        }
        /*
         * Technically since we're exiting anyway, these will be cleaned up by 
         * the garbage collector... but because we're nice people and want
         * to be invited places for Christmas, we're going to show how to clean up.
         */
        if (videoCoder != null) {
            videoCoder.close();
            videoCoder = null;
        }
        if (audioCoder != null) {
            audioCoder.close();
            audioCoder = null;
        }
        if (container != null) {
            container.close();
            container = null;
        }
        closeJavaSound();
        closeJavaVideo();
    }

    private static long millisecondsUntilTimeToDisplay(IVideoPicture picture) {
        /**
         * We could just display the images as quickly as we decode them, but it turns
         * out we can decode a lot faster than you think.
         * 
         * So instead, the following code does a poor-man's version of trying to
         * match up the frame-rate requested for each IVideoPicture with the system
         * clock time on your computer.
         * 
         * Remember that all Xuggler IAudioSamples and IVideoPicture objects always
         * give timestamps in Microseconds, relative to the first decoded item.  If
         * instead you used the packet timestamps, they can be in different units depending
         * on your IContainer, and IStream and things can get hairy quickly.
         */
        long millisecondsToSleep = 0;
        if (mFirstVideoTimestampInStream == Global.NO_PTS) {
            // This is our first time through
            mFirstVideoTimestampInStream = picture.getTimeStamp();
            // get the starting clock time so we can hold up frames
            // until the right time.
            mSystemVideoClockStartTime = System.currentTimeMillis();
            millisecondsToSleep = 0;
        } else {
            long systemClockCurrentTime = System.currentTimeMillis();
            long millisecondsClockTimeSinceStartofVideo = systemClockCurrentTime - mSystemVideoClockStartTime;
            // compute how long for this frame since the first frame in the stream.
            // remember that IVideoPicture and IAudioSamples timestamps are always in MICROSECONDS,
            // so we divide by 1000 to get milliseconds.
            long millisecondsStreamTimeSinceStartOfVideo = (picture.getTimeStamp() - mFirstVideoTimestampInStream) / 1000;
            final long millisecondsTolerance = 50; // and we give ourselfs 50 ms of tolerance
            millisecondsToSleep = (millisecondsStreamTimeSinceStartOfVideo
                    - (millisecondsClockTimeSinceStartofVideo + millisecondsTolerance));
        }
        return millisecondsToSleep;
    }

    /**
     * Opens a Swing window on screen.
     */
    /**
     * Forces the swing thread to terminate; I'm sure there is a right
     * way to do this in swing, but this works too.
     */
    private static void closeJavaVideo() {
        System.exit(0);
    }

    private static void openJavaSound(IStreamCoder aAudioCoder) throws LineUnavailableException {
        AudioFormat audioFormat = new AudioFormat(aAudioCoder.getSampleRate(),
                (int) IAudioSamples.findSampleBitDepth(aAudioCoder.getSampleFormat()),
                aAudioCoder.getChannels(),
                true, /* xuggler defaults to signed 16 bit samples */
                false);
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        mLine = (SourceDataLine) AudioSystem.getLine(info);
        /**
         * if that succeeded, try opening the line.
         */
        mLine.open(audioFormat);
        /**
         * And if that succeed, start the line.
         */
        mLine.start();


    }

    private static void playJavaSound(IAudioSamples aSamples) {
        /**
         * We're just going to dump all the samples into the line.
         */
        byte[] rawBytes = aSamples.getData().getByteArray(0, aSamples.getSize());
        mLine.write(rawBytes, 0, aSamples.getSize());
    }

    private static void closeJavaSound() {
        if (mLine != null) {
            /*
             * Wait for the line to finish playing
             */
            mLine.drain();
            /*
             * Close the line.
             */
            mLine.close();
            mLine = null;
        }
    }

    private static void openJavaVideo(IStreamCoder videoCoder) {
        mScreen = new VideoImage();
        mScreen.setPreferredSize(new Dimension(videoCoder.getWidth(), videoCoder.getHeight()));
        mScreen.setLocationRelativeTo(null);
    }
}
将openJavaVideo方法移动到视频流检测器中:

openJavaVideo(videoCoder);
更改了主体的第一部分:

public static void main(String[] args) {

        String filename = "http://techslides.com/demos/sample-videos/small.mp4";

        // Let's make sure that we can actually convert video pixel formats.
        if (!IVideoResampler.isSupported(IVideoResampler.Feature.FEATURE_COLORSPACECONVERSION)) {
            throw new RuntimeException("you must install the GPL version of Xuggler (with IVideoResampler support) for this demo to work");
        }

        // Create a Xuggler container object
        IContainer container = IContainer.make();

        // Open up the container
        if (container.open("http://techslides.com/demos/sample-videos/small.mp4", IContainer.Type.READ, null) < 0) {
            throw new IllegalArgumentException("could not open file: " + filename);
        }
publicstaticvoidmain(字符串[]args){
字符串文件名=”http://techslides.com/demos/sample-videos/small.mp4";
//让我们确保我们可以真正转换视频像素格式。
如果(!IVideoResampler.isSupported(IVideoResampler.Feature.Feature\u colorspace转换)){
抛出新的RuntimeException(“您必须安装Xuggler的GPL版本(支持IVideResampler),此演示才能正常工作”);
}
//创建一个Xuggler容器对象
IContainer容器=IContainer.make();
//打开容器
如果(容器打开(“http://techslides.com/demos/sample-videos/small.mp4,IContainer.Type.READ,null)<0){
抛出新的IllegalArgumentException(“无法打开文件:+filename”);
}
事实上,重要的部分是:

if (container.open("http://techslides.com/demos/sample-videos/small.mp4", IContainer.Type.READ, null) < 0) {
            throw new IllegalArgumentException("could not open file: " + filename);
        }
if(容器打开(“http://techslides.com/demos/sample-videos/small.mp4,IContainer.Type.READ,null)<0){
抛出新的IllegalArgumentException(“无法打开文件:+filename”);
}

我想到了另一个想法,也许值得一试

  • 创建一个JavaFX应用程序
  • 在其中添加web浏览器,请选中webengine
  • 创建一个包含html播放器的模板网页,或在服务器中加载该网页,该网页接受文件id,然后创建一个网页,为该文件创建播放器,类似于youtube,然后自动播放
  • 如果你能做到这一点,这将是一个更好的主意

    webengine和javaFX有一些示例代码。一旦你加载了一个页面,比如youtube或vimeo并在那里播放了一段视频,那么sky就是极限:)

    请参见:,只需参考javaFX代码示例(你不需要任何Swing代码)

    因此,将您的视频编码为(例如h264编码的mp4)并将其放置在http服务器上,您可以通过http从JavaFX客户端加载视频数据。确保您的客户端是

    这可能足以满足您的需要


    如果您需要一些更高级的东西,JavaFX也支持,您可以在上面阅读并查看是否需要(您可能不需要)。我没有关于设置http实时流媒体服务器的说明,也没有指向internet上某个地方的关于如何设置的链接(如果您想这样做,您必须自己进行研究)



    另外,请注意,我将转换为JavaFX来回答以下问题:。如果您想在较低的层次上了解此类视频播放是如何完成的,这是很有用的。但是,我不建议在制作项目的视频播放中使用此方法,而只是使用内置的JavaFX MediaPlayer。

    我没有找到任何可以使用的演示实施那个计划。你能帮我找一个吗?谢谢
    if (container.open("http://techslides.com/demos/sample-videos/small.mp4", IContainer.Type.READ, null) < 0) {
                throw new IllegalArgumentException("could not open file: " + filename);
            }
    
    import javafx.application.Application;
    import javafx.scene.*;
    import javafx.scene.media.*;
    import javafx.stage.Stage;
    
    public class VideoPlayerExample extends Application {
      public static void main(String[] args) throws Exception { launch(args); }
      @Override public void start(final Stage stage) throws Exception {
        final MediaPlayer oracleVid = new MediaPlayer(
          new Media("http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv")
        );
        stage.setScene(new Scene(new Group(new MediaView(oracleVid)), 540, 208));
        stage.show();
    
        oracleVid.play();
      }
    }