JavaCV教程:视频流/直播/回放/Mp4/RTSP/RTMP/FLV等进行切片转hls流播放

JavaCV教程:视频流/直播/回放/Mp4/RTSP/RTMP/FLV等进行切片转hls流播放

系列专栏
流媒体相关技术
JavaCV流媒体教程
JavaCV异常报错汇总
海康摄像头SDK二次开发实例

本文参考JavaCV开发详解之23:hls视频录制,m3u8切片录制和fmp4切片录制详解

Maven依赖

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.4</version>
</dependency>

代码实现

package com.junction;

import static org.bytedeco.ffmpeg.global.avcodec.av_packet_unref;

import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;

/**
 * @ClassName: HlsPush
 * @Description: hls流切片
 * @author: banmajio
 * @date: 2020-12-11
 */
public class Test {

	/**
	 * @Title: push
	 * @Description: hls切片
	 * @param input  可以是一个InputStream的流、动态图片(apng,gif等等),视频文件(mp4,flv,avi等等),流媒体地址(http-flv,rtmp,rtsp等等)
	 * @param output hls切片存放地址
	 * @return: void
	 * @throws org.bytedeco.javacv.FrameGrabber.Exception
	 * @throws org.bytedeco.javacv.FrameRecorder.Exception
	 **/
	public void push(String input, String output)
			throws org.bytedeco.javacv.FrameGrabber.Exception, org.bytedeco.javacv.FrameRecorder.Exception {
		FFmpegFrameGrabber grabber = null;// 采集器
		FFmpegFrameRecorder recorder = null;// 解码器
		int bitrate = 2500000;// 比特率
		double framerate;// 帧率
		int err_index = 0;// 推流过程中出现错误的次数
		int timebase;// 时钟基
		long dts = 0, pts = 0;// pkt的dts、pts时间戳
		try {

			// 开启ffmpeg日志级别;QUIET是屏蔽所有,可选INFO、DEBUG、ERROR等
			avutil.av_log_set_level(avutil.AV_LOG_INFO);
			FFmpegLogCallback.set();
			grabber = new FFmpegFrameGrabber(input);
			grabber.start();

			// 异常的framerate,强制使用25帧
			if (grabber.getFrameRate() > 0 && grabber.getFrameRate() < 100) {
				framerate = grabber.getFrameRate();
			} else {
				framerate = 25.0;
			}

			bitrate = grabber.getVideoBitrate();// 获取到的比特率 0

			recorder = new FFmpegFrameRecorder(output, grabber.getImageWidth(), grabber.getImageHeight(), 0);
			// 设置比特率
			recorder.setVideoBitrate(bitrate);
			// h264编/解码器
			recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
			// 设置音频编码
			recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
			// 视频帧率(保证视频质量的情况下最低25,低于25会出现闪屏)
			recorder.setFrameRate(framerate);
			// 关键帧间隔,一般与帧率相同或者是视频帧率的两倍
			recorder.setGopSize((int) framerate);
			// 解码器格式
			recorder.setFormat("hls");
			// 单个切片时长,单位是s,默认为2s
			recorder.setOption("hls_time", "60");
			// HLS播放的列表长度,0标识不做限制
			recorder.setOption("hls_list_size", "0");
			// 设置切片的ts文件序号起始值,默认从0开始,可以通过此项更改
			recorder.setOption("start_number", "120");
//			recorder.setOption("hls_segment_type","mpegts");
			// 自动删除切片,如果切片数量大于hls_list_size的数量,则会开始自动删除之前的ts切片,只保 留hls_list_size个数量的切片
			// recorder.setOption("hls_flags","delete_segments");
			// ts切片自动删除阈值,默认值为1,表示早于hls_list_size+1的切片将被删除
			// recorder.setOption("hls_delete_threshold","1");
			/*
			 * hls的切片类型: 'mpegts':以MPEG-2传输流格式输出ts切片文件,可以与所有HLS版本兼容。 'fmp4':以Fragmented
			 * MP4(简称:fmp4)格式输出切片文件,类似于MPEG-DASH,fmp4文件可用于HLS version 7和更高版本。
			 */
//			recorder.setOption("hls_segment_type","mpegts");

			AVFormatContext fc = null;
			fc = grabber.getFormatContext();
			recorder.start(fc);
			// 清空探测时留下的缓存
//			grabber.flush();

			AVPacket pkt = null;

			for (int no_pkt_index = 0; no_pkt_index < 5 && err_index < 5;) {
				pkt = grabber.grabPacket();
				if (pkt == null || pkt.size() <= 0 || pkt.data() == null) {
					Thread.sleep(1);
					no_pkt_index++;
					continue;
				}
				// 获取到的pkt的dts,pts异常,将此包丢弃掉。
				if (pkt.dts() == avutil.AV_NOPTS_VALUE && pkt.pts() == avutil.AV_NOPTS_VALUE || pkt.pts() < dts) {
					err_index++;
					av_packet_unref(pkt);
					continue;
				}
				// 矫正dts,pts
				pkt.pts(pts);
				pkt.dts(dts);
				err_index += (recorder.recordPacket(pkt) ? 0 : 1);
				// pts,dts累加
				timebase = grabber.getFormatContext().streams(pkt.stream_index()).time_base().den();

				pts += (timebase / (int) framerate);
				dts += (timebase / (int) framerate);
			}
		} catch (Exception e) {
			grabber.stop();
			grabber.close();
			if (recorder != null) {
				recorder.stop();
				recorder.release();
			}
		} finally {
			grabber.stop();
			grabber.close();
			if (recorder != null) {
				recorder.stop();
				recorder.release();
			}
		}
	}

	public static void main(String[] args)
			throws org.bytedeco.javacv.FrameGrabber.Exception, org.bytedeco.javacv.FrameRecorder.Exception {
		Test test = new Test();
		test.push("E:\\test.mp4",
				"D:\\nginx\\nginx-rtmp-win32\\nginx-rtmp-win32-master\\temp\\hls\\test\\banmajio.m3u8");
	}

}
上一篇:JavaCV开发详解之30:使用javacv拉取rtsp视频流,rtsp解复用器详解。如何把rtsp调教的服服帖帖,让rtsp拉流不再丢包


下一篇:HomeAssistant 集成 ffmpeg 播放 RTSP RTMP HTTP