bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.53k stars 1.58k forks source link

How to convert byte[] to RTSP #2055

Closed zhoutian94 closed 1 year ago

zhoutian94 commented 1 year ago

Is there a possible to convert byte[] of container data that continually received to RTSP using JavaCV。

I tried as follow but got an error i can't fix it :

`java.lang.NullPointerException: Cannot read the array length because "this.samples_out" is null
    at org.bytedeco.javacv.FFmpegFrameRecorder.recordSamples(FFmpegFrameRecorder.java:1180)
    at org.bytedeco.javacv.FFmpegFrameRecorder.record(FFmpegFrameRecorder.java:1021)
    at org.bytedeco.javacv.FFmpegFrameRecorder.record(FFmpegFrameRecorder.java:1010)
    at org.jfjy.jvc.DHAVToRTSPConverter.convertDHAVtoRTSP(DHAVToRTSPConverter.java:63)
    at org.jfjy.jvc.DHAVToRTSPConverter$1.apply(DHAVToRTSPConverter.java:22)
    at org.jfjy.jvc.DHAVToRTSPConverter$1.apply(DHAVToRTSPConverter.java:19)`

can anyone tell me how to do please

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class DHAVToRTSPConverter {
    static FFmpegFrameRecorder recorder;

    public static void main(String[] args) {
        ApiService apiService = new ApiService();
        Long login = apiService.login("10.3.0.54", 8801, "admin", "xxx");
        apiService.startRealPlay(new RealPlayCallback<Long, Integer, byte[]>() {
            @Override
            public void apply(Long aLong, Integer integer, byte[] bytes) {
                convertDHAVtoRTSP(new ByteArrayInputStream(bytes));
            }
        }, 0, 0);
        while (true) {

        }
    }

    public static void convertDHAVtoRTSP(InputStream dhavStreamUrl) {
        try {
            String rtspStreamUrl = "rtsp://127.0.0.1:8554/live";
            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(dhavStreamUrl);
            grabber.setFormat("dhav");

            grabber.start();

            if (null == recorder) {
                recorder = new FFmpegFrameRecorder(rtspStreamUrl, 1280, 720);
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
                recorder.setFormat("rtsp");
                recorder.setAudioChannels(0);
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);

                recorder.start(grabber.getFormatContext());
            }

            Frame frame;
            while ((frame = grabber.grabFrame()) != null) {
                recorder.record(frame);
            }

            grabber.stop();
            recorder.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
saudet commented 1 year ago

It depends on what is in that byte[] array.

zhoutian94 commented 1 year ago

It depends on what is in that byte[] array.

hi saudet! thanks for you reply, the data in byte array is the container data which name is 'dhav'

saudet commented 1 year ago

That sounds like something supported by FFmpeg. Try to call recorder.start() instead of recorder.start(grabber.getFormatContext())

zhoutian94 commented 1 year ago

yeah , you are right. But when i replaced with recorder.start(),the new error has occurred,

org.bytedeco.javacv.FFmpegFrameRecorder$Exception: No audio output stream (Is audioChannels > 0 and has start() been called?) (For more details, make sure FFmpegLogCallback.set() has been called.)
    at org.bytedeco.javacv.FFmpegFrameRecorder.recordSamples(FFmpegFrameRecorder.java:1154)
    at org.bytedeco.javacv.FFmpegFrameRecorder.record(FFmpegFrameRecorder.java:1021)
    at org.bytedeco.javacv.FFmpegFrameRecorder.record(FFmpegFrameRecorder.java:1010)
    at org.jfjy.jvc.Test.convertDHAVtoRTSP(Test.java:55)
    at org.jfjy.jvc.Test$1.apply(Test.java:22)
    at org.jfjy.jvc.Test$1.apply(Test.java:19)
    at org.jfjy.ch2ji.ecctv.dh.module.RealPlayModule$1.invoke(RealPlayModule.java:35)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at com.sun.jna.CallbackReference$DefaultCallbackProxy.invokeCallback(CallbackReference.java:585)
    at com.sun.jna.CallbackReference$DefaultCallbackProxy.callback(CallbackReference.java:616)

then ,I changed recorder.setAudioChannels(0); to recorder.setAudioChannels(1); but the error msg is same.

then I tried to ignore audio data by remove recorder.setAudioChannels and change recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); to recorder.setAudioCodec(avcodec.AV_CODEC_ID_NONE);

but still the same

saudet commented 1 year ago

Please make sure that FFmpegLogCallback.set() has been called.

saudet commented 1 year ago

What's the messages that you get in the log?

zhoutian94 commented 1 year ago

Thanks for your good patience, when i set recorder.setAudioCodec(avcodec.AV_CODEC_ID_NONE); the logs is :

Info: Input #0, dhav, from 'java.io.ByteArrayInputStream@1e38d9e9':

Info:   Duration: 
Info: N/A
Info: , start: 
Info: 1688981687.000000
Info: , bitrate: 
Info: N/A
Info: 

Info:   Stream #0:0
Info: : Audio: pcm_s16le, 16000 Hz, 1 channels, s16, 256 kb/s
Info: 

Warning: [libopenh264 @ 00000256caf5efc0] [OpenH264] this = 0x00000256caf5f940, Warning:layerId(0) doesn't support profile(578), change to UNSPECIFIC profile

Warning: [libopenh264 @ 00000256caf5efc0] [OpenH264] this = 0x00000256caf5f940, Warning:bEnableFrameSkip = 0,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.

Info: Output #0, rtsp, to 'rtsp://127.0.0.1:8554/live':

Info:   Metadata:

Info:     encoder         : 
Info: Lavf60.3.100
Info: 

Info:   Stream #0:0
Info: : Video: h264 (Constrained Baseline), yuv420p, 1280x720, q=2-31, 400 kb/s
Info: , 
Info: 30 fps, 
Info: 90k tbn
Info: 

org.bytedeco.javacv.FFmpegFrameRecorder$Exception: No audio output stream (Is audioChannels > 0 and has start() been called?) (For more details, make sure FFmpegLogCallback.set() has been called.)
……

when i replace it to recorder.setAudioChannels(1); recorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE);, the log is

Info: Input #0, dhav, from 'java.io.ByteArrayInputStream@1e38d9e9':

Info:   Duration: 
Info: N/A
Info: , start: 
Info: 1688982097.000000
Info: , bitrate: 
Info: N/A
Info: 

Info:   Stream #0:0
Info: : Audio: pcm_s16le, 16000 Hz, 1 channels, s16, 256 kb/s
Info: 

Warning: [libopenh264 @ 000002735a23efc0] [OpenH264] this = 0x000002735a23e6c0, Warning:layerId(0) doesn't support profile(578), change to UNSPECIFIC profile

Warning: [libopenh264 @ 000002735a23efc0] [OpenH264] this = 0x000002735a23e6c0, Warning:bEnableFrameSkip = 0,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.

Info: Output #0, rtsp, to 'rtsp://127.0.0.1:8554/live':

Info:   Metadata:

Info:     encoder         : 
Info: Lavf60.3.100
Info: 

Info:   Stream #0:0
Info: : Video: h264 (Constrained Baseline), yuv420p, 1280x720, q=2-31, 400 kb/s
Info: , 
Info: 30 fps, 
Info: 90k tbn
Info: 

Info:   Stream #0:1
Info: : Audio: pcm_s16le, 44100 Hz, mono, s16, 705 kb/s
Info: 

Info: Input #0, dhav, from 'java.io.ByteArrayInputStream@6221f555':

Info:   Duration: 
Info: N/A
Info: , start: 
Info: 1688982097.000000
Info: , bitrate: 
Info: N/A
Info: 

Info:   Stream #0:0
Info: : Audio: pcm_s16le, 16000 Hz, 1 channels, s16, 256 kb/s
Info: 

org.bytedeco.javacv.FFmpegFrameRecorder$Exception: No audio output stream (Is audioChannels > 0 and has start() been called?) (For more details, make sure FFmpegLogCallback.set() has been called.)

looks still the same

saudet commented 1 year ago

You might want to try libx264 instead of libopenh264.