h264文件提取一帧帧数据

本文描述了解决在开发中循环播放H264视频文件时遇到的问题,包括使用JavaCV逐帧提取导致的花屏和数据解析问题,最终通过合并小帧与大帧实现稳定传输的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、背景

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

2、解决过程

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

3、最终代码

package com.mf.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.function.Consumer;

public class VideoHandler {

    private static int sleepTime = 40; //控制视频流发送的速度,避免出现视频播放加速的情况
    
    public static void extractFrame(InputStream inputStream, Consumer<ByteBuffer> callback) throws IOException {
        LinkedList<Integer> cacheList = new LinkedList<>();
        ByteBuffer byteBuffer = ByteBuffer.allocate(2 * 1024 * 1024);

        while (true) {
            int value = inputStream.read();
            if (value == -1) break;
            cacheList.addLast(value);
            if (cacheList.size() < 4) {
                continue;
            }
            if (ishead(cacheList)) break;
            else {
                cacheList.removeFirst();
            }
        }
        cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));

        cacheList.clear();

        while (true) {
            int value = inputStream.read();
            if (value == -1) break;
            cacheList.addLast(value);
            if (cacheList.size() < 4) {
                continue;
            }
            if (ishead(cacheList)) {
                if(byteBuffer.position() < 50){
                    cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
                    cacheList.clear();
                    continue;
                }

                if (callback != null) {
                    callback.accept(byteBuffer);
                }

                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                byteBuffer.clear();
                cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
                cacheList.clear();
            } else {
                byteBuffer.put((byte) cacheList.get(0).intValue());
                cacheList.removeFirst();
            }
        }

        cacheList.forEach(temp -> byteBuffer.put((byte) temp.intValue()));
        if (callback != null) {
            callback.accept(byteBuffer);
        }
    }

    private static boolean ishead(LinkedList<Integer> list){
        if (list.size() !=4) return false;
        int v1 = list.get(0);
        int v2 = list.get(1);
        int v3 = list.get(2);
        int v4 = list.get(3);
        if((v1 == 0 && v2==0 && v3==1) || (v1 == 0 && v2==0 && v3==0 && v4 ==1))
            return true;
        else return false;
    }

    public static void main(String[] args) {
        try (FileInputStream inputStream = new FileInputStream("D:\\tmp-data\\1694511149969.h264");){
            extractFrame(inputStream,buffer -> System.out.println(buffer.position()));
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值