视频转流

阅读: 评论:0

视频转流

视频转流

之前弄过一次转流,rtsp转rtmp。之前的方法

本次采用另一种方式。这里仅做简单记录,方便后期再次使用时查看。

本实例只是推流,修改一下工具类参数也可用于转流。

先说一下思路,将转流的链接存redis,定期查redis是否还有该链接,有就继续转,没有就暂停转流(业务需求这样设计,实现定时关闭不必要的转流)

pom文件

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

VideoUtils(转流工具类也有参考网上的项目)


//import org.bytedeco.javacpp.avcodec;
import dis.service.RedisService;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class VideoUtils {@Autowiredprivate RedisService redisService;/* public static void main(String[] args) throws Exception {System.out.println(&#");String rtmpPath = "rtmp://localhost:1935/live/YFZX2";String rtspPath ="rtmp://58.200.131.2:1935/livetv/gxtv";// "rtmp://58.200.131.2:1935/livetv/hunantv";//"rtsp://admin:admin88888@192.168.100.200:554/h264/ch34/sub/av_stream";int audioRecord =1; // 0 = 不录制,1=录制boolean saveVideo = false;push(rtmpPath,rtspPath,audioRecord,saveVideo);System.out.println(&#");}*//*** @param newurl* @param oldurl* @param audioRecord* @param saveVideo* @throws Exception*/public  void push(String newurl,String oldurl,String uuid,int audioRecord,boolean saveVideo ) throws Exception  {// 使用rtsp的时候需要使用 FFmpegFrameGrabber,不能再用 FrameGrabberint width = 1024,height = 576;FFmpegFrameGrabber grabber = ateDefault(oldurl);//grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重grabber.setOption("rtmp_transport", "tcp");grabber.setImageWidth(width);grabber.setImageHeight(height);System.out.println("grabber start");grabber.start();// 流媒体输出地址,分辨率(长,高),是否录制音频(0:不录制/1:录制)FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(newurl,width,height, audioRecord);recorder.setInterleaved(true);recorder.setVideoOption("crf","28");//recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 28recorder.setFormat("flv"); // rtmp的类型recorder.setFrameRate(25);recorder.setImageWidth(width);recorder.setImageHeight(height);//recorder.setPixelFormat(0); // yuv420precorder.AudioCodec());System.out.println("recorder start");recorder.start();System.out.println("all start!!");int count = 0;//boolean exit  = false;while(true){count++;// Frame frame = abImage();Frame frame;if(audioRecord==1){frame&#ab();}else{frame&#abImage();}/// Frame frame = abImage();if(frame == null){continue;}if(count % 100 == 0){System.out.println(newurl+"count="+count);if(count % 1000 == 0){CacheObject("video:"+uuid)==null){System.out.println(newurl+"已停止");break;}}}d(frame);//Thread.sleep(1000/50);}grabber.stop();lease();recorder.stop();lease();}
}

VideoController(传入的url是需要转流的地址经过url编码,比如rtmp%3a%2f%2f58.200.131.2%3a1935%2flivetv%2fhunantv)

另外就是线程池,这里自己其实也不知道应不应该使用。

urrent.ThreadFactoryBuilder;
import web.domain.AjaxResult;
import dis.service.RedisService;
import com.ruoyi.video.utils.VideoUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.t.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;import java.util.UUID;
import urrent.*;
@RefreshScope
@RestController
@RequestMapping("video")
public class VideoController {@Value("${p:localhost:1935}")private String rtmpaddress;@Autowiredprivate RedisService redisService;@Autowiredprivate VideoUtils videoUtils;//url : rtmp%3a%2f%2f58.200.131.2%3a1935%2flivetv%2fgxtv//rtmp%3a%2f%2f58.200.131.2%3a1935%2flivetv%2fhunantv@PostMapping("getPublicUrl")public AjaxResult getPublicUrl(@RequestParam("url")String url){if(url==null||url.equals("")){("链接不能为空");}String result= UUID.randomUUID().toString().replace("-", "").toUpperCase();String newurl="rtmp://"+rtmpaddress+"/live/"+result;int audioRecord =1; // 0 = 不录制,1=录制声音boolean saveVideo = false;redisService.setCacheObject("video:"+result,url,12L, TimeUnit.HOURS);//线程池ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());ute(()-> {try {videoUtils.push(newurl,url,result,audioRecord,saveVideo);} catch (Exception e) {e.printStackTrace();}});singleThreadPool.shutdown();return AjaxResult.success("成功",newurl);}@RequestMapping("stopPublicUrl")public AjaxResult stopPublicUrl(String newurl){String url&#placeAll("rtmp://(.*)/live/","");url="video:"+url;redisService.deleteObject(url);return AjaxResult.success("成功");}
}

项目是基于ruoyi-cloud写的,所以reids操作类如果没有的话可以复制下面的。


import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import urrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.HashOperations;
import org.RedisTemplate;
import org.ValueOperations;
import org.springframework.stereotype.Component;/*** spring redis 工具类* * @author ruoyi**/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisService {@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @param unit 时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){pire(key, timeout, unit);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();(key);}/*** 删除单个对象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 删除集合对象** @param collection 多个对象* @return*/public long deleteObject(final Collection collection){return redisTemplate.delete(collection);}/*** 缓存List数据** @param key 缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** @param key 缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> long setCacheSet(final String key, final Set<T> dataSet){Long count = redisTemplate.opsForSet().add(key, dataSet);return count == null ? 0 : count;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key Redis键* @param hKey Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();(key, hKey);}/*** 获取多个Hash中的数据** @param key Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表* * @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}

项目仅供参考,另外nginx大家可以直接网上下载,配置rtmp模块,或者直接点击下载。

 

本文发布于:2024-02-01 08:26:48,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170674720835233.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:视频
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23