bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.42k stars 1.57k forks source link

How to solve error “AAC with no global headers is currently not supported” #2066

Closed zhoutian94 closed 11 months ago

zhoutian94 commented 11 months ago

Discussed in https://github.com/bytedeco/javacv/discussions/2065

Originally posted by **zhoutian94** July 18, 2023 I'm trying to transcode dhav (one of the container format) to RTSP By JavaCV(FFmpegFrameGrabber + FFmpegFrameRecorder) , It's fine when i transcoding dhav to RTMP , but when I change to RTSP ,error occurred: ``` Error: [rtsp @ 0000002318df7c30] AAC with no global headers is currently not supported. Exception in thread "pool-1-thread-2" java.lang.RuntimeException: org.bytedeco.javacv.FFmpegFrameRecorder$Exception: avformat_write_header error() error -1094995529: Could not write header to 'rtsp://127.0.0.1:8554/myapp/orange2' (For more details, make sure FFmpegLogCallback.set() has been called.) at org.jfjy.jvc.GetBytes2PipedStreamAndPushRTMP$2.run(GetBytes2PipedStreamAndPushRTMP.java:116) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: org.bytedeco.javacv.FFmpegFrameRecorder$Exception: avformat_write_header error() error -1094995529: Could not write header to 'rtsp://127.0.0.1:8554/myapp/orange2' (For more details, make sure FFmpegLogCallback.set() has been called.) at org.bytedeco.javacv.FFmpegFrameRecorder.startUnsafe(FFmpegFrameRecorder.java:969) at org.bytedeco.javacv.FFmpegFrameRecorder.start(FFmpegFrameRecorder.java:437) at org.bytedeco.javacv.FFmpegFrameRecorder.start(FFmpegFrameRecorder.java:432) at org.jfjy.jvc.GetBytes2PipedStreamAndPushRTMP.grabAndPush(GetBytes2PipedStreamAndPushRTMP.java:215) at org.jfjy.jvc.GetBytes2PipedStreamAndPushRTMP$2.run(GetBytes2PipedStreamAndPushRTMP.java:100) ... 3 more ``` the key code is ```java public static synchronized void grabAndPush(InputStream inputStream, String pushAddress, String pushPotocol) throws Exception { avutil.av_log_set_level(AV_LOG_DEBUG); FFmpegLogCallback.set(); FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream,0); long startTime = System.currentTimeMillis(); grabber.start(); AVFormatContext avFormatContext = grabber.getFormatContext(); int streamNum = avFormatContext.nb_streams(); if (streamNum < 1) { log.error("no media!"); return; } int frameRate = (int) grabber.getVideoFrameRate(); if (0 == frameRate) { frameRate = 15; } log.info("frameRate[{}],duration[{}]secs,number streams[{}]", frameRate, avFormatContext.duration() / 1000000, avFormatContext.nb_streams()); for (int i = 0; i < streamNum; i++) { AVStream avStream = avFormatContext.streams(i); AVCodecParameters avCodecParameters = avStream.codecpar(); log.info("stream index[{}],codec type[{}],codec ID[{}]", i, avCodecParameters.codec_type(), avCodecParameters.codec_id()); } int frameWidth = grabber.getImageWidth(); int frameHeight = grabber.getImageHeight(); int audioChannels = grabber.getAudioChannels(); log.info("frameWidth[{}],frameHeight[{}],audioChannels[{}]", frameWidth, frameHeight, audioChannels); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(pushAddress, frameWidth, frameHeight, audioChannels); recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); recorder.setInterleaved(true); switch (pushPotocol) { case "rtsp" -> { recorder.setFormat("rtsp"); } case "rtmp" -> { recorder.setFormat("flv"); } } log.info("push protocol:{}| grabber format:{} | recorder format:{}",pushPotocol,grabber.getFormat(),recorder.getFormat()); recorder.setFrameRate(frameRate); recorder.setAudioCodec(AV_CODEC_ID_AAC); log.info("grabber audio codec name :{}|recorder audio codec name :{}",grabber.getAudioCodecName(),recorder.getAudioCodecName()); recorder.setGopSize(frameRate * 2); recorder.setAudioChannels(grabber.getAudioChannels()); startTime = System.currentTimeMillis(); avFormatContext.max_interleave_delta(0); avFormatContext.flags(avformat.AVFMT_TS_NONSTRICT); recorder.setTimestamp(0); recorder.start(avFormatContext); Frame frame; int videoFrameNum = 0; int audioFrameNum = 0; int dataFrameNum = 0; AVPacket packet; long lastDTS = 0; while ((packet = grabber.grabPacket()) != null) { if (packet.pts() == AV_NOPTS_VALUE) { if (packet.dts() != AV_NOPTS_VALUE) { packet.pts(packet.dts()); lastDTS = packet.dts(); } else { packet.pts(lastDTS + 1); packet.dts(packet.pts()); lastDTS = packet.pts(); } } else { if (packet.dts() != AV_NOPTS_VALUE) { if (packet.dts() < lastDTS) { packet.dts(lastDTS + 1); } lastDTS = packet.dts(); } else { packet.dts(packet.pts()); lastDTS = packet.dts(); } } if (packet.pts() < packet.dts()) { packet.pts(packet.dts()); } recorder.recordPacket(packet); Thread.sleep(1); } log.info("push complete,videoFrameNum[{}],audioFrameNum[{}],dataFrameNum[{}],耗时[{}]秒", videoFrameNum, audioFrameNum, dataFrameNum, (System.currentTimeMillis() - startTime) / 1000); recorder.close(); grabber.close(); } ``` After googled , I tried fowllowing : - set avFormatContext.flags(avformat.AVFMT_GLOBALHEADER); no use - set recorder.setAudioOption("flags", "+global_header"); no use - set `recorder.setAudioOption("flags", "global_header"); recorder.setVideoOption("flags", "global_header"); `, no use could someone guide me on this that will be grateful! These mabay can help,about the dhav (snapshot) : ``` Input #0, dhav, from '.\videostream': Duration: 00:00:25.00, start: 1689678599.000000, bitrate: 2360 kb/s Stream #0:0: Audio: pcm_s16le, 16000 Hz, 1 channels, s16, 256 kb/s Stream #0:1: Video: h264 (High), yuvj420p(pc, bt470bg/bt470bg/bt709), 720x1280, 25 fps, 50 tbr, 1k tbn ```
zhoutian94 commented 11 months ago

ok, I figure out, just add recorder.setAudioBitrate(grabber.getAudioBitrate()); , dhav to rtsp is ok