Xuggler教程:转码和媒体修改
在之前的教程中,我對視頻處理Xuggler進(jìn)行了簡短介紹 。 在這一部分中,我們將看到Xuggler和FFmpeg提供的一些更令人興奮的功能,例如視頻轉(zhuǎn)碼和媒體修改。 不要忘記Xuggler是一個Java庫,可用于實(shí)時解壓縮,處理和壓縮錄制的視頻或?qū)崟r視頻。
Xuggler提供了兩種不同的編程API,可用于同一目的。 首先,我們有MediaTool API :
MediaTool是一個簡單的應(yīng)用程序編程接口(API),用于對Java中的視頻進(jìn)行解碼,編碼和修改。 MediaTool隱藏了許多容器,編解碼器和其他內(nèi)容的細(xì)節(jié),因此您可以專注于媒體而不是工具。 就是說,MediaTool仍然提供對基礎(chǔ)Xuggler對象的訪問,因此,如果需要,您可以進(jìn)行精細(xì)的控制。
還有Xuggler Advanced API ,它使您可以深入研究視頻操作的細(xì)節(jié),但又增加了一層復(fù)雜性。
首先,我們將使用MediaTool API ,在隨后的教程中,我們還將處理Advanced API。
讓我們開始將媒體從一種格式轉(zhuǎn)碼為另一種格式。 代碼轉(zhuǎn)換是一種編碼到另一種編碼的直接數(shù)模轉(zhuǎn)換。 通常在目標(biāo)設(shè)備不支持格式或存儲容量有限(要求減小文件大小)或?qū)⒉患嫒莼蜻^時的數(shù)據(jù)轉(zhuǎn)換為更好支持的格式或現(xiàn)代格式的情況下執(zhí)行此操作。 轉(zhuǎn)碼通常是一個有損過程 ,其中“有損”壓縮是一種數(shù)據(jù)編碼方法,為了達(dá)到其目標(biāo),它會丟棄(丟失)某些數(shù)據(jù),結(jié)果是,對數(shù)據(jù)進(jìn)行解壓縮會產(chǎn)生與原始數(shù)據(jù)不同的內(nèi)容,盡管足夠相似,以某種方式有用。
讓我們看一些用于轉(zhuǎn)碼的高級代碼,稍后我將詳細(xì)解釋。
package com.javacodegeeks.xuggler;import com.xuggle.mediatool.IMediaReader; import com.xuggle.mediatool.IMediaViewer; import com.xuggle.mediatool.IMediaWriter; import com.xuggle.mediatool.ToolFactory;public class TranscodingExample {private static final String inputFilename = "c:/myvideo.mp4";private static final String outputFilename = "c:/myvideo.flv";public static void main(String[] args) {// create a media readerIMediaReader mediaReader = ToolFactory.makeReader(inputFilename);// create a media writerIMediaWriter mediaWriter = ToolFactory.makeWriter(outputFilename, mediaReader);// add a writer to the reader, to create the output filemediaReader.addListener(mediaWriter);// create a media viewer with stats enabledIMediaViewer mediaViewer = ToolFactory.makeViewer(true);// add a viewer to the reader, to see the decoded mediamediaReader.addListener(mediaViewer);// read and decode packets from the source file and// and dispatch decoded audio and video to the writerwhile (mediaReader.readPacket() == null) ;}}只需幾行代碼,我們就可以將MPEG-4輸入文件轉(zhuǎn)換為FLV文件。 我們首先創(chuàng)建一個IMediaReader ,用于讀取和解碼媒體。 它打開一個媒體容器,從中讀取數(shù)據(jù)包,解碼數(shù)據(jù),然后將有關(guān)數(shù)據(jù)的信息分發(fā)到任何已注冊的IMediaListener對象。 這是IMediaWriter類起作用的地方。 它對媒體進(jìn)行編碼和解碼,同時處理音頻和視頻流。 為了使事情變得更有趣,我們還將IMediaViewer附加到我們的閱讀器上。 它用作調(diào)試工具,使我們可以在解碼視頻時觀看視頻。 此外,在此過程中,我們還會看到各種統(tǒng)計信息。 請注意,該類處于實(shí)驗(yàn)?zāi)J?#xff0c;這意味著它有一些可能會掛起的錯誤,因此請謹(jǐn)慎處理。
本質(zhì)上,使用上面的代碼,我們將兩個偵聽器IMediaWriter和IMediaViewer附加到IMediaReader對象,并在讀取器讀取和解碼源文件中的數(shù)據(jù)包的同時處理回調(diào)。 這是在“ while”循環(huán)中執(zhí)行的。 如果我們使用示例輸入文件運(yùn)行該應(yīng)用程序,將顯示類似于以下的屏幕:
該過程完成后(由于我們正在同時實(shí)時查看,因此該過程將與源視頻文件一樣長),將以FLV格式創(chuàng)建一個新的輸出文件。
讓我們從命令行使用Ffmpeg來比較輸入和輸出文件:
 ffmpeg.exe -ic:/myvideo.mp4 
 似乎流1編解碼器的幀速率與容器的幀速率不同:59.92(14981/250)-> 29.96(14981/500) 
 從'c:/myvideo.mp4'輸入#0,mov,mp4,m4a,3gp,3g2,mj2: 
 元數(shù)據(jù): 
 major_brand:mp42 
 minor_version:0 
 兼容品牌:isomavc1mp42 
 持續(xù)時間:00:04:20.96,開始:0.000000,比特率:582 kb / s 
 流#0.0(und):音頻:aac,44100 Hz,立體聲,s16、115 kb / s 
 流#0.1(und):視頻:h264,yuv420p,480×270 [PAR 1:1 DAR 16:9],464 kb / s,29.96 fps,29.96 tbr,29962 tbn,59.92 tbc 
在原始視頻文件中,容器為MPEG-4 ,有兩個流:使用44100Hz的AAC的音頻流和使用H.264的視頻流。
 ffmpeg.exe -ic:/myvideo.flv 
 似乎流0編解碼器的幀速率與容器的幀速率不同:1000.00(1000/1)-> 29.97(30000/1001) 
 從'c:/myvideo.flv'輸入#0 flv: 
 元數(shù)據(jù): 
 持續(xù)時間:261 
 寬度:480 
 高度:270 
 videodatarate:62 
 幀率:30 
 videocodecid:2 
 音頻數(shù)據(jù)率:62 
 音頻采樣率:44100 
 音頻樣本大小:16 
 立體聲:真 
 音頻編解碼器:2 
 文件大小:43117478 
 持續(xù)時間:00:04:20.98,開始:0.000000,比特率:128 kb / s 
 流#0.0:視頻:flv,yuv420p,480×270、64 kb / s,29.97 tbr,1k tbn,1k tbc 
 流#0.1:音頻:mp3,44100 Hz,2聲道,s16,64 kb / s 
轉(zhuǎn)碼后,生成的Flash視頻文件使用FLV視頻流和MP3音頻流。
現(xiàn)在,我們準(zhǔn)備使用Xuggler修改媒體文件。 但是在編寫代碼之前,我們需要了解MediaTool的工作原理 :
MediaTool使用事件偵聽器范例。 寫入器會自動作為“偵聽器”添加到讀取器,并接收所有解碼的媒體。 IMediaViewer和IMediaWriter接口(查看器和編寫器實(shí)際上是什么)實(shí)現(xiàn)IMediaListener接口,并且可以作為偵聽器添加到IMediaReader。
我們通過前面的示例確認(rèn)了這一點(diǎn)。 問題是,為了對輸入文件進(jìn)行各種修改 ,我們必須建立一個“媒體管道”。 我們創(chuàng)建IMediaTool的自定義實(shí)現(xiàn),然后以鏈?zhǔn)椒绞皆诿總€工具上設(shè)置偵聽器,以便它們將數(shù)據(jù)從一個傳遞到另一個。
假設(shè)我們希望在視頻中添加靜態(tài)圖像,同時希望減少音頻量。 在這種情況下,我們將創(chuàng)建兩個自定義IMediaTool對象:
- StaticImageMediaTool:拍攝視頻圖片并在屏幕上的特定位置標(biāo)記靜態(tài)圖像文件。
 - VolumeAdjustMediaTool:按恒定因子調(diào)整音量。
 
另外,我們創(chuàng)建一個IMediaWriter對象,該對象將用于創(chuàng)建輸出文件。 通過所有這些,我們創(chuàng)建了一條鏈,如下所示:
讀取器-> addStaticImage-> reduceVolume->寫入器
讓我們看看實(shí)現(xiàn)以上所有功能的代碼:
package com.javacodegeeks.xuggler;import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.ShortBuffer;import javax.imageio.ImageIO;import com.xuggle.mediatool.IMediaReader; import com.xuggle.mediatool.IMediaTool; import com.xuggle.mediatool.IMediaWriter; import com.xuggle.mediatool.MediaToolAdapter; import com.xuggle.mediatool.ToolFactory; import com.xuggle.mediatool.event.IAudioSamplesEvent; import com.xuggle.mediatool.event.IVideoPictureEvent;public class ModifyMediaExample {private static final String inputFilename = "c:/myvideo.mp4";private static final String outputFilename = "c:/myvideo.flv";private static final String imageFilename = "c:/jcg_logo_small.png";public static void main(String[] args) {// create a media readerIMediaReader mediaReader = ToolFactory.makeReader(inputFilename);// configure it to generate BufferImagesmediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);IMediaWriter mediaWriter = ToolFactory.makeWriter(outputFilename, mediaReader);IMediaTool imageMediaTool = new StaticImageMediaTool(imageFilename);IMediaTool audioVolumeMediaTool = new VolumeAdjustMediaTool(0.1);// create a tool chain:// reader -> addStaticImage -> reduceVolume -> writermediaReader.addListener(imageMediaTool);imageMediaTool.addListener(audioVolumeMediaTool);audioVolumeMediaTool.addListener(mediaWriter);while (mediaReader.readPacket() == null) ;}private static class StaticImageMediaTool extends MediaToolAdapter {private BufferedImage logoImage;public StaticImageMediaTool(String imageFile) {try {logoImage = ImageIO.read(new File(imageFile));} catch (IOException e) {e.printStackTrace();throw new RuntimeException("Could not open file");}}@Overridepublic void onVideoPicture(IVideoPictureEvent event) {BufferedImage image = event.getImage();// get the graphics for the imageGraphics2D g = image.createGraphics();Rectangle2D bounds = new Rectangle2D.Float(0, 0, logoImage.getWidth(), logoImage.getHeight());// compute the amount to inset the time stamp and // translate the image to that positiondouble inset = bounds.getHeight();g.translate(inset, event.getImage().getHeight() - inset);g.setColor(Color.WHITE);g.fill(bounds);g.setColor(Color.BLACK);g.drawImage(logoImage, 0, 0, null);// call parent which will pass the video onto next tool in chainsuper.onVideoPicture(event);}}private static class VolumeAdjustMediaTool extends MediaToolAdapter {// the amount to adjust the volume byprivate double mVolume;public VolumeAdjustMediaTool(double volume) {mVolume = volume;}@Overridepublic void onAudioSamples(IAudioSamplesEvent event) {// get the raw audio bytes and adjust it's valueShortBuffer buffer = event.getAudioSamples().getByteBuffer().asShortBuffer();for (int i = 0; i < buffer.limit(); ++i) {buffer.put(i, (short) (buffer.get(i) * mVolume));}// call parent which will pass the audio onto next tool in chainsuper.onAudioSamples(event);}}}與往常一樣,我們首先創(chuàng)建一個IMediaReader并在調(diào)用IMediaListener.onVideoPicture時使用setBufferedImageTypeToGenerate方法生成BufferedImage圖像。 為了將我們的自定義圖像覆蓋在實(shí)際的視頻圖片上,這是必要的。 然后,我們創(chuàng)建IMediaWriter和媒體工具對象,并如上所述配置工具鏈。 讓我們仔細(xì)看看自定義媒體工具。
首先,我們有StaticImageMediaTool類。 它擴(kuò)展了MediaToolAdapter并覆蓋了onVideoPicture方法,因?yàn)槲覀兿M褂眠@一方法來處理視頻流。 在構(gòu)造函數(shù)中,我們已經(jīng)使用ImageIO.read方法加載了一個圖像文件。 JavaCodeGeeks徽標(biāo)用于此目的(實(shí)際上是其縮小版本)。 然后,在已實(shí)現(xiàn)的onVideoPicture方法中,我們通過調(diào)用IVideoPictureEvent.getImage獲得基礎(chǔ)的BufferedImage并創(chuàng)建一個Graphics2D對象。 然后,我們使用Graphics.drawImage方法覆蓋靜態(tài)圖像。 最后,我們調(diào)用父級onVideoPicture方法,該方法會將視頻傳遞到鏈中的下一個工具。
 然后,我們有了VolumeAdjustMediaTool。 它還擴(kuò)展了MediaToolAdapter ,但覆蓋了onAudioSamples方法,該方法在對音頻樣本進(jìn)行解碼或編碼后調(diào)用。 在那里,我們通過調(diào)用IAudioSamplesEvent.getAudioSamples來獲取原始音頻字節(jié),并使用相應(yīng)的ShortBuffer類調(diào)整其值。 再次,在自定義處理之后,我們調(diào)用父onAudioSamples方法,該方法會將音頻傳遞到鏈中的下一個工具。 如果現(xiàn)在運(yùn)行此應(yīng)用程序,我們將在原始視頻的頂部看到添加的圖像,并且音頻音量將大大降低。 
  而已。 Xuggler支持的轉(zhuǎn)碼和媒體處理。 與往常一樣,您可以下載為本教程創(chuàng)建的Eclipse項目 。 請繼續(xù)關(guān)注JavaCodeGeeks上的更多Xuggler教程! 別忘了分享! 
相關(guān)文章:
- Xuggler視頻處理簡介
 - Xuggler教程:幀捕獲和視頻創(chuàng)建
 - 使用wowza和xuggler將RTMP轉(zhuǎn)換為RTSP
 
翻譯自: https://www.javacodegeeks.com/2011/02/xuggler-tutorial-transcoding-media.html
總結(jié)
以上是生活随笔為你收集整理的Xuggler教程:转码和媒体修改的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 人大金仓发布三款数据库新品 面向市场需求
 - 下一篇: 完美单身