bytedeco/javacv

converting avi-format-video file to m3u8 with Video codec not found.

Open

#2,317 opened on Feb 18, 2025

View on GitHub
 (3 comments) (0 reactions) (0 assignees)Java (1,583 forks)batch import
help wantedquestion

Repository metrics

Stars
 (6,985 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

It works fine when I convert mp4-format-video file to m3u8 with encryption,but I try a avi video file,it occurs this problem:


org.bytedeco.javacv.FFmpegFrameRecorder$Exception: avcodec_find_encoder() error: Video codec not found. (For more details, make sure FFmpegLogCallback.set() has been called.)
	at org.bytedeco.javacv.FFmpegFrameRecorder.startUnsafe(FFmpegFrameRecorder.java:537)
	at org.bytedeco.javacv.FFmpegFrameRecorder.start(FFmpegFrameRecorder.java:437)
	at org.bytedeco.javacv.FFmpegFrameRecorder.start(FFmpegFrameRecorder.java:432)
	at com.zzhua.controller.HlsEncryptConverter.convertToEncryptedHls(HlsEncryptConverter.java:65)
	at com.zzhua.controller.HlsEncryptConverter.main(HlsEncryptConverter.java:120)

following dependencies: javacv.version => 1.5.9 ffmpeg-platform => 6.0-1.5.9

import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;

public class HlsEncryptConverter {


    public static void convertToEncryptedHls(String inputPath, String outputDir, String hlsBaseUrl) throws Exception {
        // 生成随机密钥(16 bytes for AES-128)
        byte[] key = new byte[16];
        new SecureRandom().nextBytes(key);
        String keyHex = bytesToHex(key);
        
        // 生成IV(可选)
        byte[] iv = new byte[16];
        new SecureRandom().nextBytes(iv);
        String ivHex = bytesToHex(iv);

        // 保存密钥到文件
        String keyFileName = "encryption.key";
        saveKeyFile(outputDir + File.separator + keyFileName, key);

        FFmpegLogCallback.set();

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputPath);
        grabber.start();

        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
                outputDir + File.separator + "output.m3u8",
                grabber.getImageWidth(),
                grabber.getImageHeight(),
                grabber.getAudioChannels()
        );

        // 通用HLS配置
        recorder.setFormat("hls");
        recorder.setOption("hls_time", "10");          // 每个TS分片10秒
        recorder.setOption("hls_list_size", "0");       // 无限播放列表
        recorder.setOption("hls_segment_type", "mpegts");
        recorder.setOption("hls_key_info_file", generateKeyInfoFile(outputDir, keyFileName, ivHex, hlsBaseUrl));
        recorder.setOption("hls_flags", "independent_segments");
        
        // 视频编码配置(兼容性配置)
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setVideoOption("preset", "medium");
        recorder.setVideoBitrate(grabber.getVideoBitrate());
        recorder.setVideoOption("tune", "film");
        
        // 音频编码配置
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
        recorder.setAudioBitrate(grabber.getAudioBitrate());
        recorder.setSampleRate(grabber.getSampleRate());
        
        // 强制使用PTS作为时间戳
        // recorder.setOption("use_wallclock_as_timestamps", "1");
        
        recorder.start(grabber.getFormatContext());
        AVPacket packet;
        while ((packet = grabber.grabPacket()) != null) {
            try {
                recorder.recordPacket(packet);
            } catch (FrameRecorder.Exception e) {
                e.printStackTrace();
            }
        }
        recorder.setTimestamp(grabber.getTimestamp());
        recorder.stop();
        recorder.release();
        grabber.stop();
        grabber.release();

        recorder.close();
        grabber.close();
    }

    private static String generateKeyInfoFile(String outputDir, String keyFileName, String iv, String baseUrl) throws IOException {
        String keyInfoPath = outputDir + File.separator + "enc.keyinfo";
        String keyUrl = baseUrl + keyFileName;
        
        try (FileOutputStream fos = new FileOutputStream(keyInfoPath)) {
            String content = keyUrl + "\n" + outputDir + File.separator + keyFileName + "\n" + iv;
            fos.write(content.getBytes());
        }
        return keyInfoPath;
    }

    private static void saveKeyFile(String path, byte[] key) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(key);
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        try {
            /*
            // success case
            String input = "D:\\temp\\test2\\test2.mp4";
            String outputDir = "D:\\temp\\test2";
            String baseUrl = "https://your-cdn.com/";
            */

            // fail case
            String input = "D:\\temp\\test1\\test1.avi";
            String outputDir = "D:\\temp\\test1";
            String baseUrl = "https://your-cdn.com/";
            
            new File(outputDir).mkdirs();
            convertToEncryptedHls(input, outputDir, baseUrl);
            System.out.println("转换完成!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Contributor guide