• h264文件提取一帧帧数据


    1、背景

    开发中遇到个需求是循环播放某个h264视频文件,即后端不断提取

    2、解决过程

    1)首先是视频文件直接提取流定长发送,但会造成花屏。
    2)随后利用javacv一帧一帧提取字节数组发送,提取的帧是解码后的数据,内容量很大,不再属于h264编码,所以发送到前端无法解析。
    3)读取视频文件,根据001、0001手动截取一帧帧视频流,注意001、0001是每一帧的开头,转发时也要发送出去前端可以解码展示,但是python程序捕获不到帧数据。
    4)于是把小于50的信息帧数据跟后续的帧数据进行合并,在获取完整帧后再一起发送。(把视频文件每一帧的大小打印出来,发现有的帧才十几、三十几字节,这些帧要和后面的大帧合并发送,具体的值可以根据自己的实际情况进行估计)

    3、最终代码

    1. package com.mf.utils;
    2. import java.io.FileInputStream;
    3. import java.io.IOException;
    4. import java.io.InputStream;
    5. import java.nio.ByteBuffer;
    6. import java.util.LinkedList;
    7. import java.util.function.Consumer;
    8. public class VideoHandler {
    9. private static int sleepTime = 40; //控制视频流发送的速度,避免出现视频播放加速的情况
    10. public static void extractFrame(InputStream inputStream, Consumer callback) throws IOException {
    11. LinkedList cacheList = new LinkedList<>();
    12. ByteBuffer byteBuffer = ByteBuffer.allocate(2 * 1024 * 1024);
    13. while (true) {
    14. int value = inputStream.read();
    15. if (value == -1) break;
    16. cacheList.addLast(value);
    17. if (cacheList.size() < 4) {
    18. continue;
    19. }
    20. if (ishead(cacheList)) break;
    21. else {
    22. cacheList.removeFirst();
    23. }
    24. }
    25. cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
    26. cacheList.clear();
    27. while (true) {
    28. int value = inputStream.read();
    29. if (value == -1) break;
    30. cacheList.addLast(value);
    31. if (cacheList.size() < 4) {
    32. continue;
    33. }
    34. if (ishead(cacheList)) {
    35. if(byteBuffer.position() < 50){
    36. cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
    37. cacheList.clear();
    38. continue;
    39. }
    40. if (callback != null) {
    41. callback.accept(byteBuffer);
    42. }
    43. try {
    44. Thread.sleep(sleepTime);
    45. } catch (InterruptedException e) {
    46. throw new RuntimeException(e);
    47. }
    48. byteBuffer.clear();
    49. cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
    50. cacheList.clear();
    51. } else {
    52. byteBuffer.put((byte) cacheList.get(0).intValue());
    53. cacheList.removeFirst();
    54. }
    55. }
    56. cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
    57. if (callback != null) {
    58. callback.accept(byteBuffer);
    59. }
    60. }
    61. private static boolean ishead(LinkedList list){
    62. if (list.size() !=4) return false;
    63. int v1 = list.get(0);
    64. int v2 = list.get(1);
    65. int v3 = list.get(2);
    66. int v4 = list.get(3);
    67. if((v1 == 0 && v2==0 && v3==1) || (v1 == 0 && v2==0 && v3==0 && v4 ==1))
    68. return true;
    69. else return false;
    70. }
    71. public static void main(String[] args) {
    72. try (FileInputStream inputStream = new FileInputStream("D:\\tmp-data\\1694511149969.h264");){
    73. extractFrame(inputStream,buffer -> System.out.println(buffer.position()));
    74. }catch (Exception e){
    75. System.out.println(e.getMessage());
    76. }
    77. }
    78. }

  • 相关阅读:
    离线安装腾讯x5内核(附安装包下载地址)
    【华为OD机考B卷 | 100分】统计监控、需要打开多少监控器(JAVA题解——也许是全网最详)
    svn版本控制-实用篇
    Ubuntu24.04安装中文输入法
    中小企业是否需要微软活动目录联合服务(ADFS)?
    springboot+vue学习用品商店商城系统java毕业设计ucozu
    图像处理之颜色特征描述
    【ManageEngine】网络带宽管理工具
    Java final 关键字
    前端环境变量及vite中本地环境配置实践
  • 原文地址:https://blog.csdn.net/Interest1_wyt/article/details/134296369