【问题标题】:Stream h264 to javafx possibly using javacv/ffmpeg可能使用 javacv/ffmpeg 将 h264 流式传输到 javafx
【发布时间】:2018-10-04 07:29:33
【问题描述】:

我真的很想在 java fx 项目上播放视频流。

-- 短版:

我正在将 h264/avcc 风格的视频从 Android 手机流式传输到台式计算机。但是 javafx 没有一个简单的解决方案来显示流。我正在尝试使用 javacv / ffmpeg 来完成这项工作。但是我从 ffmpeg 收到错误。

1) 有没有更好的方法在 javafx 上显示流媒体视频?

2) 你有 javacv ffmpegframegrabber 的示例项目或好的教程吗?

3) 我想我可能在我的代码中遗漏了一些小细节,但我不确定我会是什么。

-- 加长版:

1) 在 android 端,我正在使用 mediarecorder 获取视频。为了获取 sps/pps 信息,我录制并保存了一个小电影到设备,然后解析 sps 和 pps 数据。

2) 接下来,在 android 上,我拆分 nalus 以满足 MTU req 并通过 udp 连接将它们发送到我的桌面

3)在我的桌面上,我重新组装 nalus(如果它们丢失数据,则将它们丢弃)并将它们提供给我提供给 framegreabber 构造函数的输入流。

-- 代码和日志:

根据我喂它的口味,错误很长而且很多。这是两个单独的示例,通常会很长地重复

[h264 @ 0000020225907a40] non-existing PPS 0 referenced
[h264 @ 0000020225907a40] decode_slice_header error
[h264 @ 0000020225907a40] no frame!

[h264 @ 00000163d8637a40] illegal aspect ratio
[h264 @ 00000163d8637a40] pps_id 3412 out of range
[AVBSFContext @ 00000163e28a0e00] Invalid NAL unit 0, skipping.

!!我知道的一个重要警告是我没有实现时间戳 我在喂 ffmpeg 时在 android 设备上创建的。我认为如果没有这个,它仍然应该显示扭曲的图像

因为我整天都在猜测和尝试,所以我已经推过了几种“口味”的数据。我只显示每个 nal 的第一部分,只要我的 sps 和 pps 正确,我相信如果正确至少会显示垃圾图像

sps: 67 80 80 1E E9 01 68 22 FD C0 36 85 09 A8
pps: 68 06 06 E2

下面是附件 B 样式。 这些都以 00 00 01 和 00 00 00 01 为前缀

Debug transfer 65 B8 40 0B E5 B8 7B 80 5B 85 
Debug transfer 41 E2 20 7A 74 34 3B D6 BE FA 
Debug transfer 41 E4 40 2F 01 E0 0C 06 EE 91 
Debug transfer 41 E6 60 3E A1 20 5A 02 3C 6D 
Debug transfer 41 E8 80 13 B0 B9 82 C3 03 F4 
Debug transfer 41 EC C0 1B A3 0C 28 F1 B0 C8 
Debug transfer 41 EE E0 1F CE 07 30 EE 05 06 
Debug transfer 41 F1 00 08 ED 80 9C 20 09 73 
Debug transfer 41 F3 20 09 E9 00 86 60 21 C3 
VideoDecoderaddPacket type: 24
Debug transfer 67 80 80 1E E9 01 68 22 FD C0 
Debug transfer 68 06 06 E2 
Debug transfer 65 B8 20 00 9F 80 78 00 12 8A 
Debug transfer 41 E2 20 09 F0 1E 40 7B 0C E0 
Debug transfer 41 E4 40 09 F0 29 30 D6 00 AE 
Debug transfer 41 E6 60 09 F1 48 31 80 99 40 
[h264 @ 000001c771617a40] non-existing PPS 0 referenced

在这里我尝试了 Avcc 风格。可以看到第一行是sps pps后跟idr再重复non idr的组合

Debug transfer 18 00 0E 67 80 80 1E E9 01 68 
Debug transfer 00 02 4A 8F 65 B8 20 00 9F C5 
Debug transfer 00 02 2F DA 41 E2 20 09 E8 0F 
Debug transfer 00 02 2C 34 41 E4 40 09 F4 20 
Debug transfer 00 02 4D 92 41 E6 60 09 FC 2B 
Debug transfer 00 02 47 02 41 E8 80 09 F0 72 
Debug transfer 00 02 52 50 41 EA A0 09 EC 0F 
Debug transfer 00 02 58 8A 41 EC C0 09 FC 6F 
Debug transfer 00 02 55 F9 41 EE E0 09 FC 6E 
Debug transfer 00 02 4D 79 41 F1 00 09 F0 3E 
Debug transfer 00 02 4D B6 41 F3 20 09 E8 64 

下面的课程是我尝试让 javacv/ffmpeg 显示视频的地方。我不认为它是一个理想的解决方案,并且正在研究 canvasfram 作为图像视图的替代品。

    public class ImageDecoder {

    private final static String TAG = "ImageDecoder ";

    private ImageDecoder(){

    }


    public static void streamImageToImageView(
            final ImageView view,
            final InputStream inputStream,
            final String format,
            final int frameRate,
            final int bitrate,
            final String preset,
            final int numBuffers
    )
    {
        System.out.println("Image Decoder Starting...");


        try(    final FrameGrabber grabber = new 
    FFmpegFrameGrabber(inputStream))
        {

            final Java2DFrameConverter converter = new Java2DFrameConverter();

            grabber.setFrameNumber(frameRate);
            grabber.setFormat(format);
            grabber.setVideoBitrate(bitrate);
            grabber.setVideoOption("preset", preset);
            grabber.setNumBuffers(numBuffers);

            System.out.println("Image Decoder waiting on grabber.start...");
            grabber.start();   //---- this call is blocking the loop

            System.out.println("Image Decoder Looping--------------------------- 
   -------- hit stop");
            while(!Thread.interrupted()){
                //System.out.println("Image Decoder Looping");
                final Frame frame = grabber.grab();
                if (frame != null){
                    final BufferedImage bufferedImage = 
    converter.convert(frame);
                    if (bufferedImage != null){

                        Platform.runLater(() -> 
    view.setImage(SwingFXUtils.toFXImage(bufferedImage, null)));
                    }else{
                        System.out.println("no buf im");
                    }
                }else{
                    System.out.println("no fr");
                    Thread.currentThread().interrupt();
                }

            }



        }catch (Exception e){
            System.out.print(TAG + e);
        }


    }






    }

非常感谢任何帮助。

【问题讨论】:

  • 我突然意识到我在我的 spspps 前面加上了类型 24,这是一个 rtp 标准而不是 h264。我意识到我完全不理解 spspps h264 标头。仍然可以使用不期待这本书的建议itu.int/rec/…

标签: android javafx ffmpeg h.264 javacv


【解决方案1】:

所以我有两个问题。

首先是我的sps pps解析方法有错误。注意第二个和第三个字节是一样的

第二个是我不小心超大了缓冲区并创建了模拟起始代码的大 0x00 填充区域。

这对我来说是一个大项目,我想帮助其他人。请访问我的网站,我在那里写了一篇关于流式传输 h264 的冗长多部分讨论

【讨论】:

  • 你的网站地址是什么?
猜你喜欢
  • 2011-08-20
  • 2016-09-28
  • 2017-11-16
  • 2018-07-12
  • 2017-08-11
  • 2021-06-24
  • 2021-04-12
  • 2019-06-13
  • 2017-07-16
相关资源
最近更新 更多