一、前言

大家好,俗话说的好,学习新的知识后要学以致用,在学习音视频的过程中,你有没有疑问,不知道音视频可以用来做什么。下面举几个例子,比较耳熟能详,被吹到风口的一些场景有:AI 视觉计算, AI 人脸识别. 细化到一些小的领域,如现在直播技术,摄像头监控拉流;其他还有抖音中的美颜,滤镜,其背后是使用的音视频领域的数字化妆技术。由此可见,音视频技术应用已经应用于我们生活的方方面面。

二、开发背景

想写这篇文章的目的是因为,我有个朋友平时喜欢刷抖音,就经常有一些视频被作者设置成了不可下载保存,朋友下次想再看的话就找不到了。 还有朋友想下载暗恋的妹纸的作品。所以就把苦闷告诉我了,作为朋友当然有义务帮助他走出困境啦,终于,Two thousand years later 的今天,这个小工具终于问世,因为时间原因,来不及写前端页面了,后面有需要的同学可以关注或者私信我,我们一起学习,另外,写本文的目的纯粹是以学习为主,如不小心被不法分子滥用以盈利为目的,与本人无关,请广大道友积极爱护学习环境,记得不要连累我。

三、核心思想

其实核心步骤就两步

1、根据抖音上复制的分享链接获取到抖音的真实地址,需要使用网络编程技术解析到视频的真实地址。

2、然后使用 ffmpeg 解码网络视频流,保存到本地。

四、主要技术点

1、主要使用 Java 与 一些网络调用的知识,例如 Restemplate 的使用,Restemplate 是 spring web 中的一个模板方法类,这里主要用到了他的两个方法(headForHeaders, exchange),当然也可以用其他的工具类或者自己去实现网络远程调用。

2、JSON 解析使用 fastjson,版本号随意,一般都可以兼容。

3、StringUtils 是使用 commons.lang3 包下面中的工具类,不要导错包啦。

4、ffmpeg 拉流使用的第三方依赖是 javacv,版本 1.4.3 版本。如需具体引用依赖,关注或者私信我。

5、如果你对于 ffmpeg 基本概念,音视频基本概念,如视频帧, 音频帧,码率等基本知识不是非常清楚,这里我只说技术的应用,关于原理的讲解,不做过多赘述,网上一搜一大堆,有兴趣可以自己去了解以下。

6、使用 javacv 中的 FFmpegFrameGrabber 帧抓取器来获取音/视频帧,用这个抓取器,可以省略原生的 API 调用的一堆复杂操作,例如打开视频流,查找解码器,判断音频帧和视频帧。

来自网上的一段介绍/概括

FFmpegFrameGrabber 用于采集/抓取视频图像和音频采样。封装了检索流信息,自动猜测视频解码格式,音视频解码等具体 API,并把解码完的像素数据(可配置像素格式)或音频数据保存到 Frame 中返回等功能。

7、还可以使用 ffmpeg 命令行的方式进行下载。命令如下:

ffmpeg -i https://xxx.mp4 -c copy -f flv 艾北.flv

但是这种方式需要部署机安装 ffmpeg,所以暂时不考虑这种方式了。

8、使用 javacv 中的 FrameRecorder 录制器来把已经解码的图像像素编码成对应的编码和格式推流出去,这里保存到本地就是推流到本地文件。

以下是音视频大佬 eguid 对于 FrameRecorder 的介绍概括

FrameRecorder 用于音视频/图片的封装、编码、推流和录制保存等操作。把从 FrameGrabber 或者 FrameFilter 获取的 Frame 中的数据取出并进行编码、封装、推流发送等操作流程。为了方便理解和阅读,下文开始我们统一把 FrameRecorder 简称为:录制器。

五、详细思路

1、链接解析 &接口解析

(1)、Java 正则表达式从字符串中提取出 url。

(2)、使用 RestTemplate.headForHeaders() 方法获取某个资源的 URI 的请求头信息,并且只专注于获取 HTTP 请求头信息。

(3)、第一步中提取出的 url 在浏览器中模拟可以发现, 会重定向到一个新的地址,从请求头中获取重定向后的地址, 即从 header 中获取 location,然后从 location 中获取视频的真实 id。

(4)、根据视频真实 id 和抖音的接口去获取视频信息,如播放信息,作者信息,背景音乐信息等等,使用 json 一层一层解析出来播放地址的 url。

2、ffmpeg 拉流并保存

(1)、使用 ffmpeg 获取 url 视频帧的第一帧,检测视频是否是空视频。

(2)、创建视频流录制器,设置视频参数,分辨率,格式,输出位置。

(3)、循环获取视频帧,使用录制器 recorder 逐帧录制视频帧。

六、核心代码

1、使用正则提取 url
    /**
* 正则表达式提取 url
* @param text
* @return
*/
public static String pickURI(String text) {
// eg: text = "5.1 GV:/ 一出场就给人一种江南的感觉%刘亦菲 %精彩片段 %歌曲红马 https://v.douyin.com/e614JkV/ 腹制佌lian接,打开Dou音搜索,直接观kan视頻!";
Pattern pattern = Pattern.compile("https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
return matcher.group();
}
return "";
}
 
2、发起网络调用,解析 json 获取真实地址
    public final static String DOU_YIN_WEB_API = "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=";

    /**
* 根据赋值的分享码下载抖音视频
* @param text
* @throws FrameGrabber.Exception
* @throws FrameRecorder.Exception
*/
public static String douYin(String text) throws FrameGrabber.Exception, FrameRecorder.Exception {
//
String url = pickURI(text);
RestTemplate client = new RestTemplate();
//
HttpHeaders headers = client.headForHeaders(url);
String location = headers.getLocation().toString();
String vid = StringUtils.substringBetween(location, "/video/", "/?"); RestTemplate restTemplate = new RestTemplate();
HttpHeaders queryHeaders = new HttpHeaders();
queryHeaders.set(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36");
HttpEntity<String> entity = new HttpEntity<>(queryHeaders);
ResponseEntity<JSONObject> response = restTemplate.exchange(DOU_YIN_WEB_API + vid, HttpMethod.GET, entity, JSONObject.class); if(response.getStatusCodeValue() != 200) {
return "";
}
JSONObject body = response.getBody();
assert body != null;
List<JSONObject> list = JSONArray.parseObject(body.getJSONArray("item_list").toJSONString(), new TypeReference<List<JSONObject>>(){});
if(list.size() == 0) {
return "";
}
JSONObject item = list.get(0);
JSONObject video = item.getJSONObject("video");
JSONObject playAddr = video.getJSONObject("play_addr");
JSONArray urlList = playAddr.getJSONArray("url_list");
List<String> urlListArr = JSONArray.parseObject(urlList.toJSONString(), new TypeReference<List<String>>(){});
if(urlListArr.size() == 0) {
return "";
}
return urlListArr.get(0);
// VideoConvert.record(finalAddr, "/home/yinyue/upload/红马.flv");
}

3、ffmpeg 拉流并保存
    /**
* 转存视频流
* @param input
* @param outFile
* @throws FrameGrabber.Exception
* @throws FrameRecorder.Exception
*/
public static void record(String input, String outFile) throws FrameGrabber.Exception, FrameRecorder.Exception {
FrameGrabber grabber = new FFmpegFrameGrabber(input);
grabber.start();
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
Frame frame = grabber.grab();
opencv_core.IplImage image = null;
if(frame == null) {
System.out.println("第一帧为空,请检查视频源");
return;
}
image = converter.convert(frame);
FrameRecorder recorder = FrameRecorder.createDefault(outFile, frame.imageWidth, frame.imageHeight);
recorder.setVideoCodec(AV_CODEC_ID_H264);
recorder.setFormat("flv");
recorder.setFrameRate(25);
recorder.setGopSize(25);
recorder.start();
Frame saveFrame;
while((frame = grabber.grab()) != null) {
saveFrame = converter.convert(image);
// 获取类型, 视频或者音频
// EnumSet<Frame.Type> videoOrAudio = saveFrame.getTypes();
// 录制视频
recorder.record(saveFrame);
}
recorder.close();
}

七、运行截图

运行完成后本地成功生成了下载的视频文件

八、作者心得

我们生在一个技术百花齐放,日新月异的年代,生于这个时代即是幸运也是悲哀,在如此浩瀚无穷无尽的知识更迭浪潮中,很难保证全能,尽善尽美;有的人专注于算法,有的人专注与数据处理,还有的人动手能力不行,但是理论能力极强,比如著名物理学家杨振宁,有的人专注于如何应用落地,致力于将技术应用于社会生活,所以,如果本文对你有用,请不吝赞赏,如果你感觉内容过于浅薄或者是令你感到不适,也请缄默不言,互相留一份体面。

Javacv 音视频小工具 - 下载抖音视频的更多相关文章

  1. python+fiddler 抓取抖音数据包并下载抖音视频

    这个我们要下载视频,那么肯定首先去找抖音视频的url地址,那么这个地址肯定在json格式的数据包中,所以我们就去专门查看json格式数据包 这个怎么找我就不用了,直接看结果吧 你找json包,可以选大 ...

  2. Python音视频开发:消除抖音短视频Logo的图形化工具实现

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...

  3. Python音视频开发:消除抖音短视频Logo和去电视台标

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  4. (数据科学学习手札80)用Python编写小工具下载OSM路网数据

    本文对应脚本已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们平时在数据可视化或空间数据分析的过程中经常会 ...

  5. 用 Python 下载抖音无水印视频

    说起抖音,大家或多或少应该都接触过,如果大家在上面下载过视频,一定知道我们下载的视频是带有水印的,那么我们有什么方式下载不带水印的视频呢?其实用 Python 就可以做到,下面我们来看一下. 很多人学 ...

  6. Python MoviePy中文教程导览及可执行音视频剪辑工具下载

    ☞ ░ 前往老猿Python博文目录 ░ <Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载>是老猿两个关于moviepy的专栏<PyQt+moviepy ...

  7. Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  8. Python爬虫---爬取抖音短视频

    目录 前言 抖音爬虫制作 选定网页 分析网页 提取id构造网址 拼接数据包链接 获取视频地址 下载视频 全部代码 实现结果 待解决的问题 前言 最近一直想要写一个抖音爬虫来批量下载抖音的短视频,但是经 ...

  9. 今日头条、抖音、西瓜、火山、微视、陌陌等自媒体平台小视频批量下载工具v1.1.0(视频搬运福利)

    前言 目前各大自媒体平台爆火,网络流量暴涨,各大自媒体平台的小视频为广大个广告主带来了如泉涌般的的视频流量,更给广大的自媒体小编带来了丰厚的利益回报,想要创做更多的自媒体内容着实不易,下面给广大的小视 ...

  10. 用Google Brain的机器学习项目:Magenta,教神经网络学抖音小姐姐作曲。

    先上我们要学习的小姐姐 的美照.. 一.配置环境 1.自己配置环境:python,tensorflow,bazel(编译),java.然后下载magenta(https://github.com/te ...

随机推荐

  1. mongodb删除指定字段

    db.getCollection('geoServer').update({},{$unset:{longitude:null,latitude:null}},{ multi: true}) 实测有效 ...

  2. LoadRunner——block(块)技术

    一般情况下,loadrunner中的事务是统一执行的,多个事务所执行的次数是相同的,对于不同的事务执行不同的次数就要用到block(块)技术 block(块)技术主要应用于在一个脚本中实现不同事务.不 ...

  3. nuxt中asyncData和fetch的区别

    asyncData作用于页面pages,在组件中不能使用,并且asyncData中没有this,如果想要给data中的数据赋值,要在asyncData函数中return出去 fetch 作用于组件中c ...

  4. this和箭头函数的this

    https://www.cnblogs.com/lfri/p/11872696.html https://www.ruanyifeng.com/blog/2018/06/javascript-this ...

  5. 字符流---->字符过滤流 缓冲流 : -----> printWrite用法:和BufferedReader用法

    printWrite用法:1.创建字符节点流FileWriter fw = new FileWriter("Files\\bufchar.txt");2创建字符过滤流 PrintW ...

  6. 使用idea从零编写SpringCloud项目-Feign

    ps:Fegin和Ribbon 其实是差不多的东西,Fegin里面也是集成了Ribbon,不过咱们写代码不是要优雅嘛,使用Feign就会优雅很多了,看着比直接使用Ribbon舒坦一点 就不重新构建项目 ...

  7. IOS文件下载时,文件名的处理

    string contentType = MimeMapping.GetMimeMapping(name);var isIOS = false; if (Request.UserAgent != nu ...

  8. FCC 中级算法题 Everything Be True

    Everything Be True 所有的东西都是真的! 完善编辑器中的every函数,如果集合(collection)中的所有对象都存在对应的属性(pre),并且属性(pre)对应的值为真.函数返 ...

  9. 用requests库的get( )函数访问搜狗网站20次

    代码: import requests from bs4 import BeautifulSoup def getHTMLText(url): try: r=requests.get(url,time ...

  10. django静态文件,form表单提交数据,连接mysql,操作ORM

    静态文件配置 1. 什么是静态文件 css js img ... 2. 静态文件的存储位置 ''' 我们在创建Django项目的时候,没有生成static目录,我们会把静态文件存储在static目录下 ...