Xuggler教程:幀捕獲和視頻創建

注意:這是我們的“ Xuggler開發教程 ”系列的一部分。

到目前為止,在我們的Xuggler教程系列中,我們已經對視頻處理的Xuggler進行了介紹,并討論了轉碼和媒體修改 。 在本教程中,我們將看到如何解碼視頻和捕獲幀,以及如何從頭開始創建視頻。

讓我們開始解碼視頻流并以預定義的時間間隔捕獲一些幀。 例如,可以使用它來制作媒體文件的縮略圖 。 為此,我們將再次使用MediaTool API ,這是用于解碼,編碼和修改視頻的高級API。

概念是打開媒體文件,循環播放特定的視頻流,并以特定的間隔捕獲相應的幀,將其轉換為圖像,然后將二進制內容轉儲到文件中。 這是所有這些代碼的樣子:

package com.javacodegeeks.xuggler;import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;import javax.imageio.ImageIO;import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.MediaListenerAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.xuggler.Global;public class VideoThumbnailsExample {public static final double SECONDS_BETWEEN_FRAMES = 10;private static final String inputFilename = "c:/Java_is_Everywhere.mp4";private static final String outputFilePrefix = "c:/snapshots/mysnapshot";// The video stream index, used to ensure we display frames from one and// only one video stream from the media container.private static int mVideoStreamIndex = -1;// Time of last frame writeprivate static long mLastPtsWrite = Global.NO_PTS;public static final long MICRO_SECONDS_BETWEEN_FRAMES = (long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);public static void main(String[] args) {IMediaReader mediaReader = ToolFactory.makeReader(inputFilename);// stipulate that we want BufferedImages created in BGR 24bit color spacemediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);mediaReader.addListener(new ImageSnapListener());// read out the contents of the media file and// dispatch events to the attached listenerwhile (mediaReader.readPacket() == null) ;}private static class ImageSnapListener extends MediaListenerAdapter {public void onVideoPicture(IVideoPictureEvent event) {if (event.getStreamIndex() != mVideoStreamIndex) {// if the selected video stream id is not yet set, go ahead an// select this lucky video streamif (mVideoStreamIndex == -1)mVideoStreamIndex = event.getStreamIndex();// no need to show frames from this video streamelsereturn;}// if uninitialized, back date mLastPtsWrite to get the very first frameif (mLastPtsWrite == Global.NO_PTS)mLastPtsWrite = event.getTimeStamp() - MICRO_SECONDS_BETWEEN_FRAMES;// if it's time to write the next frameif (event.getTimeStamp() - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {String outputFilename = dumpImageToFile(event.getImage());// indicate file writtendouble seconds = ((double) event.getTimeStamp()) / Global.DEFAULT_PTS_PER_SECOND;System.out.printf("at elapsed time of %6.3f seconds wrote: %s\n",seconds, outputFilename);// update last write timemLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;}}private String dumpImageToFile(BufferedImage image) {try {String outputFilename = outputFilePrefix + System.currentTimeMillis() + ".png";ImageIO.write(image, "png", new File(outputFilename));return outputFilename;} catch (IOException e) {e.printStackTrace();return null;}}}}

這看起來似乎有些令人不知所措,但確實非常簡單。 讓我為您提供一些詳細信息。 我們首先從輸入文件創建IMediaReader 。 媒體讀取器用于讀取和解碼媒體。 由于我們希望將捕獲的視頻幀作為圖像進行處理,因此我們使用setBufferedImageTypeToGenerate方法來表示這一點。 閱讀器打開一個媒體容器,從中讀取數據包,解碼數據,然后將有關數據的信息分發到任何已注冊的IMediaListener對象。 這是我們的自定義類ImageSnapListener起作用的地方。

我們的偵聽器擴展了MediaListenerAdapter ,它是實現IMediaListener接口的適配器(提供空方法)。 通知實現此接口的對象有關視頻處理期間生成的事件的信息。 我們只關心處理視頻事件,因此我們僅實現IMediaListener.onVideoPicture方法。 在其中,我們使用提供的IVideoPictureEvent對象查找正在處理的流(僅視頻)。

由于我們希望在特定時間捕獲幀,因此我們不得不在時間戳上弄亂一點。 首先,我們通過檢查Global.NO_PTS常量的值來確保處理第一幀,該值意味著沒有為給定對象設置時間戳。 然后,如果經過了最短的時間,我們通過調用IVideoPictureEvent.getImage方法捕獲幀,該方法返回基礎BufferedImage 。 請注意,我們所說的是經過的視頻時間,而不是“實時”。 然后,我們使用ImageIO.write實用程序方法將圖像數據轉儲為PNG格式的文件。 最后,我們更新最后的寫入時間。

讓我們運行此應用程序以查看結果。 作為輸入文件,我使用的是一個古老的Sun商業廣告,它宣稱“ Java無處不在 ”。 我已經在本地下載了提供的MP4版本。 這是輸出控制臺的外觀:

在經過0.000秒時寫道:c:/snapshots/mysnapshot1298228503292.png
在10.010秒的經過時間寫道:c:/snapshots/mysnapshot1298228504014.png
在20.020秒的經過時間寫道:c:/snapshots/mysnapshot1298228504463.png

在經過時間130.063秒時寫道:c:/snapshots/mysnapshot1298228509454.png
在經過時間140.007秒時寫道:c:/snapshots/mysnapshot1298228509933.png
在經過150.017秒的時間時寫道:c:/snapshots/mysnapshot1298228510379.png

總視頻時間約為151秒,因此我們捕獲了16幀。 這是我的文件夾中捕獲的圖像的外觀:

好的,就是用來制作視頻縮略圖的。 現在讓我們看看如何從頭開始創建視頻。 作為輸入,我們將使用桌面上的順序快照 。 這可以用于基本的屏幕記錄應用程序。

為了創建視頻,與到目前為止所見的MediaTool API相比,我們將不得不采取一些更底層的方法。 不過請不要擔心,它不會很復雜。 主要思想是,我們創建一個媒體編寫器,向其中添加一些流信息,對我們的媒體(屏幕截圖圖像)進行編碼,然后關閉該編寫器。 讓我們看看用于實現此目的的代碼:

package com.javacodegeeks.xuggler;import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.concurrent.TimeUnit;import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.xuggler.ICodec;public class ScreenRecordingExample {private static final double FRAME_RATE = 50;private static final int SECONDS_TO_RUN_FOR = 20;private static final String outputFilename = "c:/mydesktop.mp4";private static Dimension screenBounds;public static void main(String[] args) {// let's make a IMediaWriter to write the file.final IMediaWriter writer = ToolFactory.makeWriter(outputFilename);screenBounds = Toolkit.getDefaultToolkit().getScreenSize();// We tell it we're going to add one video stream, with id 0,// at position 0, and that it will have a fixed frame rate of FRAME_RATE.writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_MPEG4, screenBounds.width/2, screenBounds.height/2);long startTime = System.nanoTime();for (int index = 0; index < SECONDS_TO_RUN_FOR * FRAME_RATE; index++) {// take the screen shotBufferedImage screen = getDesktopScreenshot();// convert to the right image typeBufferedImage bgrScreen = convertToType(screen, BufferedImage.TYPE_3BYTE_BGR);// encode the image to stream #0writer.encodeVideo(0, bgrScreen, System.nanoTime() - startTime, TimeUnit.NANOSECONDS);// sleep for frame rate millisecondstry {Thread.sleep((long) (1000 / FRAME_RATE));} catch (InterruptedException e) {// ignore}}// tell the writer to close and write the trailer if  neededwriter.close();}public static BufferedImage convertToType(BufferedImage sourceImage, int targetType) {BufferedImage image;// if the source image is already the target type, return the source imageif (sourceImage.getType() == targetType) {image = sourceImage;}// otherwise create a new image of the target type and draw the new imageelse {image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), targetType);image.getGraphics().drawImage(sourceImage, 0, 0, null);}return image;}private static BufferedImage getDesktopScreenshot() {try {Robot robot = new Robot();Rectangle captureSize = new Rectangle(screenBounds);return robot.createScreenCapture(captureSize);} catch (AWTException e) {e.printStackTrace();return null;}}}

我們首先從給定的輸出文件創建一個IMediaWriter 。 此類對媒體進行編碼和解碼,同時處理音頻和視頻流。 Xuggler猜測文件擴展名(在我們的情況下為MP4)的輸出格式,并適當設置一些默認值。 然后,我們使用addVideoStream方法添加新的視頻流,并提供其索引,使用的編解碼器類型 (此處為MPEG-4 )和視頻尺寸。 在此示例中,尺寸設置為等于屏幕尺寸的一半。

然后,我們執行一個循環,該循環的運行次數等于所需的幀速率乘以所需的運行時間。 在循環內部,我們按照Java2D:帶有Java屏幕快照的文章中的描述生成屏幕快照。 我們將屏幕快照作為BufferedImage檢索,并將其轉換為適當的類型( TYPE_3BYTE_BGR )(如果尚不存在)。

接下來,我們使用IMediaWriter.encodeVideo方法將圖像編碼為視頻流。 我們提供流索引,圖像,經過的視頻時間和時間單位。 然后,根據所需的幀速率,我們睡適當的時間。 循環結束后,我們將關閉編寫器,并在必要時編寫預告片,具體取決于視頻格式(這由Xuggler自動完成)。

如果我們執行該應用程序,則會創建一個視頻,其中記錄了您的桌面操作。 這是瀏覽JavaCodeGeeks網站時的靜止圖像:

伙計們,這是Xuggler的另一篇教程,描述了如何從輸入文件捕獲視頻幀以及如何使用桌面快照生成視頻。 與往常一樣,您可以下載為本教程創建的Eclipse項目 。 請繼續關注JavaCodeGeeks上的更多Xuggler教程! 別忘了分享!

相關文章:

  • Xuggler視頻處理簡介
  • Xuggler教程:轉碼和媒體修改
  • 使用wowza和xuggler將RTMP轉換為RTSP

翻譯自: https://www.javacodegeeks.com/2011/02/xuggler-tutorial-frames-capture-video.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374856.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374856.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374856.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

面向對象-原型對象

創建對象 Js中可以用構造函數模式創建對象&#xff0c;如&#xff1a; function Person(name, age, job) {this.name name;this.age age;this.job job;this.sayName function () {alert(this.name);}}var person1 new Person("Nicholas", 29, "aa");v…

索引類型

1.B樹索引 在Oracle中是通用索引&#xff0c;是創建索引時的默認索引。B樹索引可以是單列索引&#xff0c;也可以是組合/復合索引。B樹索引最多可以包括22列。 2.位圖索引 位圖索引時決策支持系統&#xff08;DSS&#xff09;和數據倉庫的理想選擇&#xff0c;它們不應該用于事…

C語言條件運算符

先看一個error error: lvalue required as left operand of assignment| i 0 ? X 1.0 : X * x;修改后 i 0 ? (X 1.0) : (X * x);也就是說條件運算符可以執行語句&#xff0c;當是賦值語句時要加括號規定優先級&#xff0c;不然會干擾程序判斷。 因為條件運算符作為三目…

EJB 3.0注入和查找簡介

介紹 Enterprise JavaBeans Specification v。3.0引入了簡化的&#xff0c;基于注釋的API&#xff0c;用于EJB注入和查找。 EJB 3.0現在是POJO&#xff0c;可以使用簡單的注釋將其注入其他組件&#xff08;例如EJB和Servlet&#xff09;。 EJB 3.0是Java EE 6的許多其他基于POJ…

SignalR + MVC5 簡單示例

SignalR MVC5 簡單示例 原文:SignalR MVC5 簡單示例本文和前一篇文章很類似&#xff0c;只不過是把 SignalR 應用在了 MVC 中 新建項目&#xff0c;選擇 MVC 模板 安裝 SignalR Install-Package Microsoft.AspNet.SignalR 在項目中添加文件夾 Hubs 在 Hubs 文件夾中添加 Sign…

Java內存模型–快速概述和注意事項

在計算中&#xff0c; 內存模型描述了線程如何通過內存進行交互&#xff0c;或更一般地&#xff0c;它指定了為分段內存或分頁內存平臺生成代碼時允許編譯器進行的假設。 在給定程序和該程序的執行跟蹤的情況下&#xff0c;它實質上描述了執行跟蹤是否是該程序的合法執行。 Jav…

6-7 統計某類完全平方數 (20 分)

本題要求實現一個函數&#xff0c;判斷任一給定整數N是否滿足條件&#xff1a;它是完全平方數&#xff0c;又至少有兩位數字相同&#xff0c;如144、676等。 函數接口定義&#xff1a; int IsTheNumber ( const int N );其中N是用戶傳入的參數。如果N滿足條件&#xff0c;則該…

C#中數組、ArrayList和List三者的區別(轉) ,加修改

在C#中數組&#xff0c;ArrayList&#xff0c;List都能夠存儲一組對象&#xff0c;那么這三者到底有什么樣的區別呢。 數組 數組在C#中最早出現的。在內存中是連續存儲的&#xff0c;所以它的索引速度非常快&#xff0c;而且賦值與修改元素也很簡單。 <span style"font…

phpmyadmin mysql Access denied for user 'root'@'localhost'問題解決

centos6.4 32位的vps上裝了lnmp以后&#xff0c;phpmyadmin無法連接mysql服務器&#xff0c;ssh命令行里mysql -uroot -p 命令后老是出現拒絕連接的情況。php程序里也是拒絕連接。嘗試過修改phpmyadmin的config.inc.php文件&#xff0c;嘗試過修改my.cnf文件&#xff0c;嘗試過…

帶有Spring和Maven教程的JAX–WS

Spring框架通過JAX-WS提供對Web服務的遠程支持&#xff0c;實際上&#xff0c;如Spring 參考文檔中所述 &#xff0c;有三種將Spring POJO服務公開為JAX-WS Web服務的方式&#xff1a; 公開基于Servlet的Web服務&#xff08;適用于Java EE 5環境&#xff09; 導出獨立的Web服…

7-2 然后是幾點 (15 分)

7-2 然后是幾點 (15 分) 有時候人們用四位數字表示一個時間&#xff0c;比如 1106 表示 11 點零 6 分。現在&#xff0c;你的程序要根據起始時間和流逝的時間計算出終止時間。 讀入兩個數字&#xff0c;第一個數字以這樣的四位數字表示當前時間&#xff0c;第二個數字表示分鐘…

CXF學習(2) helloworld

0.新建一個項目取名wsserver. pom.xml 文件如下 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd…

Hive 接口介紹(Web UI/JDBC)

Hive 接口介紹&#xff08;Web UI/JDBC&#xff09; 實驗簡介 本次實驗學習 Hive 的兩種接口&#xff1a;Web UI 以及 JDBC。 一、實驗環境說明 1. 環境登錄 無需密碼自動登錄&#xff0c;系統用戶名shiyanlou&#xff0c;密碼shiyanlou 2. 環境介紹 本實驗環境采用帶桌面的Ubu…

Java最佳實踐– Char到Byte和Byte到Char的轉換

在使用Java編程語言時&#xff0c;我們將繼續討論與建議的實踐有關的系列文章&#xff0c;我們將討論String性能調優。 特別是&#xff0c;我們將重點介紹使用默認編碼時如何有效地處理字符到字節和字節到字符的轉換。 本文總結了兩種提議的自定義方法與兩種經典方法&#xff0…

IOS-C文件的創建于初始化函數.void init() write_file()

//文件初始化 void init(){ FILE * fpNULL; fpfopen("telbook.data", "rb"); int count0; if (fpNULL) //沒有這個文件就把這個文件創建出來 { fpfopen("tellbook.data", "wb"); fwrite(&count, sizeof(count), 1, fp); fclose(…

7-3 逆序的三位數 (10 分)

7-3 逆序的三位數 (10 分) 程序每次讀入一個正3位數&#xff0c;然后輸出按位逆序的數字。注意&#xff1a;當輸入的數字含有結尾的0時&#xff0c;輸出不應帶有前導的0。比如輸入700&#xff0c;輸出應該是7。 輸入格式&#xff1a; 每個測試是一個3位的正整數。 輸出格式&a…

拋棄優啟Grub4dos和PE大多數時間可以這樣用

拋棄優啟Grub4dos和PE大多數時間可以這樣用 在能夠進入Windows的情況下&#xff0c;Grub4dos和PE大多數時間可以這樣用 http://yunpan.cn/cyuuUtUQMfmGN 提取碼 c2acGrub4dos的出現顛覆了傳統的EZBOOT光盤啟動模式&#xff0c;很多人用grub4dos來實現優盤啟動&#xff0c;同時g…

Java最佳實踐–隊列之戰和鏈接的ConcurrentHashMap

在使用Java編程語言時&#xff0c;我們將繼續討論與建議的實踐有關的系列文章&#xff0c;我們將在四個具有相關語義的流行Queue實現類之間進行性能比較。 為了使事情變得更現實&#xff0c;我們將在多線程環境下進行測試&#xff0c;以討論和演示如何將ArrayBlockingQueue &am…

HDU 5652 India and China Origins(二分 + BFS)

本文鏈接:http://www.cnblogs.com/Ash-ly/p/5398867.html 題意&#xff1a; 中國和印度之間有一片地方&#xff0c;把這片地方抽象化&#xff0c;于是就可以看成一個N * M矩陣&#xff0c;其中黑色的代表高山不能走過去&#xff0c;白色的代表平原&#xff0c;可以通行,人每次可…

C語言%.2f四舍五入

#include <stdio.h> int main() {double d 1.199;printf("%.2f", d);return 0; }輸出1.20 如果不想讓其四舍五入可以這樣&#xff1a; #include <stdio.h> #include <math.h> int main() {double d 1.199;printf("%.2f", floor(d * 1…