Javacv 音視頻小工具 - 下載抖音視頻


Javacv 音視頻小工具 - 下載抖音視頻

一、前言

大家好,俗話說的好,學習新的知識后要學以致用,在學習音視頻的過程中,你有沒有疑問,不知道音視頻可以用來做什么。下面舉幾個例子,比較耳熟能詳,被吹到風口的一些場景有: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();
    }
 
        

七、運行截圖

img

 

img

 

運行完成后本地成功生成了下載的視頻文件

img

 

八、作者心得

我們生在一個技術百花齊放,日新月異的年代,生於這個時代即是幸運也是悲哀,在如此浩瀚無窮無盡的知識更迭浪潮中,很難保證全能,盡善盡美;有的人專注於算法,有的人專注與數據處理,還有的人動手能力不行,但是理論能力極強,比如著名物理學家楊振寧,有的人專注於如何應用落地,致力於將技術應用於社會生活,所以,如果本文對你有用,請不吝贊賞,如果你感覺內容過於淺薄或者是令你感到不適,也請緘默不言,互相留一份體面。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM