Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 用视频编码视频和音频_Java_Audio_Video_Video Encoding - Fatal编程技术网

Java 用视频编码视频和音频

Java 用视频编码视频和音频,java,audio,video,video-encoding,Java,Audio,Video,Video Encoding,我试图从远程流创建一个视频文件,将其存储在硬盘上。我用简陋的视频编码。录制和创建视频文件工作正常。但是现在我想给视频添加音频 我从远程源接收JPG图像和音频数据作为字节数组。音频数据的采样率为11025,为1通道16位值 我想我仍然缺少一些关于我试图插入到视频文件中的音频数据的时基和时间戳的信息。大多数情况下,所有录制的音频都非常混乱,只能在视频的前几秒钟听到 这是我的密码: import java.awt.image.BufferedImage; import java.io.ByteArra

我试图从远程流创建一个视频文件,将其存储在硬盘上。我用简陋的视频编码。录制和创建视频文件工作正常。但是现在我想给视频添加音频

我从远程源接收JPG图像和音频数据作为字节数组。音频数据的采样率为11025,为1通道16位值

我想我仍然缺少一些关于我试图插入到视频文件中的音频数据的时基和时间戳的信息。大多数情况下,所有录制的音频都非常混乱,只能在视频的前几秒钟听到

这是我的密码:

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

import javax.imageio.ImageIO;

import io.humble.video.AudioChannel.Layout;
import io.humble.video.AudioFormat.Type;
import io.humble.video.Codec;
import io.humble.video.Encoder;
import io.humble.video.MediaAudio;
import io.humble.video.MediaPacket;
import io.humble.video.MediaPicture;
import io.humble.video.Muxer;
import io.humble.video.MuxerFormat;
import io.humble.video.PixelFormat;
import io.humble.video.Rational;
import io.humble.video.awt.MediaPictureConverter;
import io.humble.video.awt.MediaPictureConverterFactory;

public class VideoStream {
    private static final int FPS = 30;
    private static final int AUDIO_SAMPLE_RATE = 11025;
    private static final int AUDIO_SAMPLE_SIZE = 11025;

    private final String filename;
    private final long startTimestampVideo;
    private final long startTimestampAudio;
    private final Muxer muxer;
    private final Encoder videoEncoder;
    private final Encoder audioEncoder;
    private final Rational timebase;

    private MediaPicture picture;
    private MediaPictureConverter converter;
    private MediaPacket packet;
    private MediaAudio sound;

    private boolean finished = false;

    private static class EncoderTask implements Runnable {
        private final byte[] data;
        private final long timestamp;
        private final Consumer<EncoderTask> encoder;

        public EncoderTask(byte[] data, long timestamp, Consumer<EncoderTask> encoder) {
            if (encoder == null) {
                throw new IllegalArgumentException("Encoder must not be null.");
            }

            this.data = data;
            this.timestamp = timestamp;
            this.encoder = encoder;
        }

        @Override
        public void run() {
            encoder.accept(this);
        }

        public byte[] getData() {
            return data;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public Consumer<EncoderTask> getEncoder() {
            return encoder;
        }
    }

    private ExecutorService threadPool = Executors.newSingleThreadExecutor();

    public VideoStream(String filename, int width, int height, long startTimestampVideo, long startTimestampAudio)
            throws IOException, InterruptedException {
        this.filename = filename;
        this.startTimestampVideo = startTimestampVideo;
        this.startTimestampAudio = startTimestampAudio;

        this.timebase = Rational.make(1, FPS);

        this.muxer = Muxer.make(filename, null, null);

        PixelFormat.Type pixelFormat = PixelFormat.Type.PIX_FMT_YUV420P;
        Codec videoCodec = Codec.findEncodingCodec(muxer.getFormat().getDefaultVideoCodecId());
        Codec audioCodec = Codec.findEncodingCodec(muxer.getFormat().getDefaultAudioCodecId());

        this.videoEncoder = createVideoEncoder(videoCodec, width, height, pixelFormat);
        this.audioEncoder = createAudioEncoder(audioCodec);

        videoEncoder.open(null, null);
        audioEncoder.open(null, null);
        muxer.addNewStream(videoEncoder);
        muxer.addNewStream(audioEncoder);
        muxer.open(null, null);

        picture = MediaPicture.make(videoEncoder.getWidth(), videoEncoder.getHeight(), pixelFormat);
        picture.setTimeBase(timebase);

        sound = MediaAudio.make(AUDIO_SAMPLE_SIZE, AUDIO_SAMPLE_RATE, 1, Layout.CH_LAYOUT_MONO, Type.SAMPLE_FMT_S16);
        sound.setTimeBase(timebase);

        packet = MediaPacket.make();
    }

    private Encoder createVideoEncoder(Codec codec, int width, int height, PixelFormat.Type pixelFormat) {
        Encoder encoder = Encoder.make(codec);

        encoder.setWidth(width);
        encoder.setHeight(height);
        encoder.setPixelFormat(pixelFormat);
        encoder.setTimeBase(timebase);

        if (muxer.getFormat().getFlag(MuxerFormat.Flag.GLOBAL_HEADER)) {
            encoder.setFlag(Encoder.Flag.FLAG_GLOBAL_HEADER, true);
        }

        return encoder;
    }

    private Encoder createAudioEncoder(Codec codec) {
        Encoder encoder = Encoder.make(codec);

        encoder.setSampleRate(AUDIO_SAMPLE_RATE);
        encoder.setChannels(1);
        encoder.setChannelLayout(Layout.CH_LAYOUT_MONO);
        encoder.setSampleFormat(Type.SAMPLE_FMT_S16);

        if (muxer.getFormat().getFlag(MuxerFormat.Flag.GLOBAL_HEADER)) {
            encoder.setFlag(Encoder.Flag.FLAG_GLOBAL_HEADER, true);
        }

        return encoder;
    }

    public String getFilename() {
        return filename;
    }

    public synchronized void addImage(byte[] imageData, long timestamp) {
        if (!finished) {
            System.out.println("Adding image: " + (timestamp - startTimestampVideo));
            threadPool.execute(new EncoderTask(imageData, timestamp, this::encodeImage));
        }
    }

    public synchronized void addAudio(byte[] audioData, long timestamp) {
        if (!finished) {
            System.out.println("Adding audio: " + (timestamp - startTimestampAudio));
            threadPool.execute(new EncoderTask(audioData, timestamp, this::encodeAudio));
        }
    }

    public synchronized void finish() {
        if (!finished) {
            threadPool.execute(new EncoderTask(null, 0, this::finish));
        }
    }

    private synchronized void encodeImage(EncoderTask task) {
        BufferedImage jpegImage = convertImageDataToBufferedImage(task.getData());
        if (jpegImage == null) {
            return;
        }

        BufferedImage image = convertToType(jpegImage, BufferedImage.TYPE_3BYTE_BGR);

        if (converter == null) {
            converter = MediaPictureConverterFactory.createConverter(image, picture);
        }

        long t = Math.round((task.getTimestamp() - startTimestampVideo) * timebase.getDouble());
        converter.toPicture(picture, image, t);

        System.out.println("Encoding video: " + t);
        do {
            videoEncoder.encode(packet, picture);
            if (packet.isComplete()) {
                muxer.write(packet, false);
            }
        } while (packet.isComplete());
    }

    private synchronized void encodeAudio(EncoderTask task) {
        System.out.println(
                "Audio delta: " + (task.getTimestamp() - startTimestampAudio) + " timebase: " + timebase.getDouble());
        long t = Math.round((task.getTimestamp() - startTimestampAudio) * timebase.getDouble() * AUDIO_SAMPLE_RATE);

        sound.getData(0).put(task.data, 0, 0, task.data.length);
        sound.setNumSamples(task.data.length);
        sound.setTimeStamp(t);
        sound.setComplete(true);

        System.out.println("Encoding audio: " + t);
        do {
            audioEncoder.encode(packet, sound);
            if (packet.isComplete()) {
                muxer.write(packet, false);
            }
        } while (packet.isComplete());
    }

    private synchronized void finish(EncoderTask task) {
        do {
            videoEncoder.encode(packet, null);
            if (packet.isComplete()) {
                muxer.write(packet, false);
            }
        } while (packet.isComplete());
        do {
            audioEncoder.encode(packet, null);
            if (packet.isComplete()) {
                muxer.write(packet, false);
            }
        } while (packet.isComplete());

        muxer.close();
        finished = true;

        threadPool.shutdown();
    }

    private static BufferedImage convertImageDataToBufferedImage(byte[] imageData) {
        try (InputStream in = new ByteArrayInputStream(imageData)) {
            return ImageIO.read(in);
        } catch (IOException e) {
            return null;
        }
    }

    private static BufferedImage convertToType(BufferedImage sourceImage, int targetType) {
        BufferedImage image;

        if (sourceImage.getType() == targetType) {
            // if the source image is already the target type, return the source image
            image = sourceImage;
        } else {
            // otherwise create a new image of the target type and draw the new
            // image
            image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), targetType);
            image.getGraphics().drawImage(sourceImage, 0, 0, null);
        }

        return image;
    }
}
导入java.awt.image.buffereImage;
导入java.io.ByteArrayInputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.function.Consumer;
导入javax.imageio.imageio;
导入io.humble.video.AudioChannel.Layout;
导入io.humble.video.AudioFormat.Type;
导入io.humble.video.Codec;
导入io.humble.video.Encoder;
导入io.humble.video.MediaAudio;
导入io.humble.video.mediapack;
导入io.humble.video.MediaPicture;
导入io.humble.video.Muxer;
导入io.humble.video.MuxerFormat;
导入io.humble.video.PixelFormat;
导入io.humble.video.Rational;
导入io.humble.video.awt.MediaPictureConverter;
导入io.humble.video.awt.MediaPictureConverterFactory;
公共类视频流{
专用静态最终整数FPS=30;
专用静态最终整数音频采样率=11025;
专用静态最终int音频样本大小=11025;
私有最终字符串文件名;
私人最终长启动视频;
私人最终长启动音频;
专用最终多路复用器多路复用器;
专用最终编码器;
专用最终编码器;音频编码器;
私人最终合理时基;
私人媒体图片;
专用媒体图像转换器;
专用媒体包;
私人媒体音频;
private boolean finished=false;
私有静态类EncoderTask实现可运行{
私有最终字节[]数据;
私有最终长时间戳;
专用最终用户编码器;
公共编码器任务(字节[]数据、长时间戳、使用者编码器){
如果(编码器==null){
抛出新的IllegalArgumentException(“编码器不能为null”);
}
这个数据=数据;
this.timestamp=时间戳;
this.encoder=编码器;
}
@凌驾
公开募捐{
接受(这个);
}
公共字节[]getData(){
返回数据;
}
公共长getTimestamp(){
返回时间戳;
}
公共消费者getEncoder(){
返回编码器;
}
}
私有ExecutorService线程池=Executors.newSingleThreadExecutor();
公共视频流(字符串文件名、整数宽度、整数高度、长startTimestampVideo、长startTimestampAudio)
抛出IOException、InterruptedException{
this.filename=文件名;
this.starttimestamp视频=starttimestamp视频;
this.starttimestampudio=starttimestampudio;
this.timebase=Rational.make(1,FPS);
this.muxer=muxer.make(文件名,null,null);
PixelFormat.Type PixelFormat=PixelFormat.Type.PIX_FMT_YUV420P;
Codec videoCodec=Codec.findEncodingCodec(muxer.getFormat().getDefaultVideoCodecId());
Codec audioCodec=Codec.findEncodingCodec(muxer.getFormat().getDefaultAudioCodecId());
this.videoEncoder=createVideoEncoder(videoCodec、宽度、高度、像素格式);
this.audioEncoder=createAudioEncoder(audioCodec);
视频编码器。打开(空,空);
音频编码器。打开(空,空);
muxer.addNewStream(视频编码器);
muxer.addNewStream(音频编码器);
muxer.open(null,null);
picture=MediaPicture.make(videoEncoder.getWidth()、videoEncoder.getHeight()、pixelFormat);
图片。设置时基(时基);
声音=MediaAudio.make(音频采样大小、音频采样率、1、Layout.Chu Layout\u MONO、Type.SAMPLE\u FMT\u S16);
声音。设置时基(时基);
packet=mediapack.make();
}
专用编码器createVideoEncoder(编解码器编解码器,整数宽度,整数高度,像素格式。键入像素格式){
编码器=编码器.make(编解码器);
编码器。设置宽度(宽度);
编码器。设置高度(高度);
编码器.setPixelFormat(pixelFormat);
编码器。设置时基(时基);
if(muxer.getFormat().getFlag(MuxerFormat.Flag.GLOBAL_头)){
encoder.setFlag(encoder.Flag.Flag_GLOBAL_头,true);
}
返回编码器;
}
专用编码器createAudioEncoder(编解码器){
编码器=编码器.make(编解码器);
编码器.设置采样率(音频采样率);
编码器。设置通道(1);
编码器.setChannelLayout(Layout.CH_Layout_MONO);
编码器.setSampleFormat(类型.SAMPLE_FMT_S16);
if(muxer.getFormat().getFlag(MuxerFormat.Flag.GLOBAL_头)){
encoder.setFlag(encoder.Flag.Flag_GLOBAL_头,true);
}
返回编码器;
}
公共字符串getFilename(){
返回文件名;
}
公共同步的void addImage(字节[]imageData,长时间戳){
如果(!完成){
System.out.println(“添加图像:+(时间戳-startTimestampVideo));
execute(新的EncoderTask(imageData,timestamp,this::encodeImage));
}
}
公共同步void addAudio(字节[]audioData,长时间戳){
如果(!完成){
System.out.println(“添加音频:+(时间戳-startTimestampAudio));
execute(新的EncoderTask(audioData,timestamp,this::encodeAudio));
}
}
公共同步无效