導航:首頁 > 操作系統 > android多媒體框架

android多媒體框架

發布時間:2022-05-06 05:35:55

1. android開發的技術層次是指哪些

開發一個程序,android的系統框架是層層相扣,不能分開的。
應用程序層:
這個層主要指的就是用java語言編寫的運行在虛擬機上的程序,Google在最開始時就 在android系統中捆綁了一些核心的應用(核心應用的編寫必須使用應用層序框架層的API框架),例如你android手機中SMS發送短消息的程序,通訊錄等等。
應用程序框架層:
指的就是開發時所需要的API框架,開發人員是在遵守該框架的原則上,調用他們的,開發自己所需要的程序。
系統運行庫層:
用於支持應用框架層的各個組件的。就是說當開發人員使用android應用框架層時,android系統會通過一些C/C++庫來支持對我們使用的各個組件,使其能更好地為開發者服務。
linux核心層:
android的核心系統服務如安全性、內存管理、進程管理、網路協議棧和驅動模型等都依賴於Linux2.6內核,Linux內核同時也作為硬體和軟體棧之間的抽象層。
因此,你開發的程序是運行在應用程序層,開發中寫代碼調用的包,是基於應用框架層,而在應用框架中的各個組件是需要系統運行庫的支持的,例如,你要登陸查看的信息就必須訪問到SQLite資料庫,SQLite就位於系統運行庫,再有,你登入要輸入信息,肯定需要鍵盤驅動的支持,而各種驅動是依賴Linux內核的。

2. android多媒體開發,怎麼改視頻解析度

改解析度指的是什麼?電腦也不能直接改吧?

3. android.media.AsyncPlayer這個類應該怎麼用

代碼結構:

Open Core 的代碼在Android 代碼的 External/Opencore 目錄中 。這個目錄是OpenCore
的根目錄,其中包含的子目錄如下所示 :

android :這裡面是一個上層的庫,它實現了一個為Android 使用的音視頻採集,播放的介面,和DRM 數字版權管理的介面實現。

baselibs :包含數據結構和線程安全等內容的底層庫

codecs_v2 :音視頻的編解碼器,基於 OpenMAX 實現

engines :核心部分 ,多媒體 引擎的實現

extern_libs_v2 :包含了 khronos 的 OpenMAX 的頭文件

fileformats :文件格式的解析( parser )工具

nodes :提供一些PVMF 的NODE ,主要是編解碼和文件解析方面的。

oscl :操作系統兼容庫

pvmi : 輸入輸出控制的抽象介面

protocols :主要是與網路相關的 RTSP 、 RTP 、 HTTP 等協議 的相關內容

pvcommon : pvcommon 庫文件的 Android.mk 文件,沒有源文件。

pvplayer : pvplayer 庫文件的 Android.mk 文件,沒有源文件。

pvauthor : pvauthor 庫文件的 Android.mk 文件,沒有源文件。

tools_v2 :編譯工具以及一些可注冊的模塊。

本文主要介紹Android MediaPlayer的架構,主要由OpenCore 里的PV Player來實現的。

1.概述

Android的MediaPlayer包含了Audio和Video的播放功能,Music和Video兩個應用程序都是調用MediaPlayer實現的。

代碼主要分布在以下的目錄中:

JAVA程序的路徑:

packages/apps/Music/src/com/android/music/

JAVA類的路徑:

frameworks/base/media/java/android/media/MediaPlayer.java

JAVA本地調用部分(JNI):

frameworks/base/media/jni/android_media_MediaPlayer.cpp

編譯為 libmedia_jni.so

頭文件:

frameworks/base/include/media/

多媒體庫:

frameworks/base/media/libmedia/

編譯為 libmedia.so

多媒體服務:

frameworks/base/media/libmediaplayerservice/

編譯為 libmediaplayerservice.so

具體實現:

external/opencore/

編譯為 libopencoreplayer.so

libopencoreplayer.so是主要的實現部分,其他的庫基本上都是在其上建立的封裝和為建立進程間通訊的機制。

2.框架


運行的時候,大致可以分成Client和Server兩個部分,分別在兩個進程中運行,使用Binder機制實現IPC通訊。從框架結構上來看,IMediaPlayerService.h、IMediaPlayerClient.h和MediaPlayer.h三個類定義了MeidaPlayer的介面和架構,MediaPlayerService.cpp和mediaplayer.cpp兩個文件用於MeidaPlayer架構的實現,MeidaPlayer的具體功能在PVPlayer(庫libopencoreplayer.so)中的實現。

2.1 IMediaPlayerClient.h

描述一個MediaPlayer客戶端的介面

class IMediaPlayerClient: public IInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayerClient);

virtual void notify(int msg, int ext1, int ext2) = 0;

};

class BnMediaPlayerClient: public BnInterface

{

public:

virtual status_t onTransact( uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags = 0);

};

在定義中,IMediaPlayerClient類繼承IInterface,並定義了一個MediaPlayer客戶端的介面,BnMediaPlayerClient繼承了BnInterface,這是為基於Android的基礎類Binder機制實現在進程通訊而構建的。事實上,根據BnInterface類模版的定義,BnInterface類相當於雙繼承了BnInterface和ImediaPlayerClient,這是Android一種常用的定義方式。

2.2 mediaplayer.h

對外的介面類,它最主要是定義了一個MediaPlayer類:

class MediaPlayer : public BnMediaPlayerClient

{

public:

MediaPlayer();

~MediaPlayer();

void onFirstRef();

void disconnect();

status_t setDataSource(const char *url);

status_t setDataSource(int fd, int64_t offset, int64_t length);

status_t setVideoSurface(const sp& surface);

status_t setListener(const sp& listener);

status_t prepare();

status_t prepareAsync();

status_t start();

status_t stop();

status_t pause();

bool isPlaying();

status_t getVideoWidth(int *w);

status_t getVideoHeight(int *h);

status_t seekTo(int msec);

status_t getCurrentPosition(int *msec);

status_t getDuration(int *msec);

status_t reset();

status_t setAudioStreamType(int type);

status_t setLooping(int loop);

status_t setVolume(float leftVolume, float rightVolume);

void notify(int msg, int ext1, int ext2);

static sp decode(const char* url, uint32_t *pSampleRate, int*
pNumChannels);

static sp decode(int fd, int64_t offset, int64_t length, uint32_t
*pSampleRate, int* pNumChannels);

//……

}

從介面中可以看出MediaPlayer類剛好實現了一個MediaPlayer的基本操作,例如播放(start)、停止(stop)、暫停(pause)等。

另外的一個類DeathNotifier在MediaPlayer類中定義,它繼承了IBinder類中的DeathRecipient類:

class DeathNotifier: public IBinder:: DeathRecipient

{

public:

DeathNotifier() {}

virtual ~DeathNotifier();

virtual void binderDied(const wp& who);

};

事實上,MediaPlayer類正是間接地繼承了IBinder,而MediaPlayer:: DeathNotifier類繼承了IBinder::
DeathRecipient,這都是為了實現進程間通訊而構建的。

2.3 IMediaPlayer.h

主要的的內容是一個實現MediaPlayer功能的介面:

class IMediaPlayer: public IInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayer);

virtual void disconnect() = 0;

virtual status_t setVideoSurface(const sp& surface) = 0;

virtual status_t prepareAsync() = 0;

virtual status_t start() = 0;

virtual status_t stop() = 0;

virtual status_t pause() = 0;

virtual status_t isPlaying(bool* state) = 0;

virtual status_t getVideoSize(int* w, int* h) = 0;

virtual status_t seekTo(int msec) = 0;

virtual status_t getCurrentPosition(int* msec) = 0;

virtual status_t getDuration(int* msec) = 0;

virtual status_t reset() = 0;

virtual status_t setAudioStreamType(int type) = 0;

virtual status_t setLooping(int loop) = 0;

virtual status_t setVolume(float leftVolume, float rightVolume) = 0;

};

class BnMediaPlayer: public BnInterface

{

public:

virtual status_t onTransact( uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags = 0);

};

在IMediaPlayer類中,主要定義MediaPlayer的功能介面,這個類必須被繼承才能夠使用。值得注意的是,這些介面和MediaPlayer類的介面有些類似,但是它們並沒有直接的關系。事實上,在MediaPlayer類的各種實現中,一般都會通過調用IMediaPlayer類的實現類來完成。

2.4 頭文件IMediaPlayerService.h

描述一個MediaPlayer的服務,定義方式如下所示:

class IMediaPlayerService: public IInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayerService);

virtual sp create(pid_t pid, const
sp& client, const char* url) = 0;

virtual sp create(pid_t pid, const
sp& client, int fd, int64_t offset, int64_t length) =
0;

virtual sp decode(const char* url, uint32_t *pSampleRate, int*
pNumChannels) = 0;

virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t
*pSampleRate, int* pNumChannels) = 0;

};

class BnMediaPlayerService: public BnInterface

{

public:

virtual status_t onTransact( uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags = 0);

};

由於有純虛函數,IMediaPlayerService
以及BnMediaPlayerService必須被繼承實現才能夠使用,在IMediaPlayerService定義的create和decode等介面,事實上是必須被繼承者實現的內容。注意,create的返回值的類型是sp,這個IMediaPlayer正是提供實現功能的介面。

3 實現

3.1 App

在packages/apps/Music/src/com/android/music/里的MediaPlaybackService.java文件中,包含了對MediaPlayer的調用。

在MediaPlaybackService.java中包含對包的引用:

import android.media.MediaPlayer;

在MediaPlaybackService類的內部,定義了MultiPlayer類:

private class MultiPlayer {

private MediaPlayer mMediaPlayer = new MediaPlayer();

}

MultiPlayer類中使用了MediaPlayer類,其中有一些對這個MediaPlayer的調用,調用的過程如下所示:

mMediaPlayer.reset();

mMediaPlayer.setDataSource(path);

mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

reset,setDataSource和setAudioStreamType等介面就是通過JAVA本地調用(JNI)來實現的。

3.2 Jni

在frameworks/base/media/jni/android_media_MediaPlayer.cpp中實現,其中android_media_MediaPlayer_reset函數的實現如下所示:

static void android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)

{

sp mp = getMediaPlayer(env, thiz);

if (mp == NULL ) {

jniThrowException(env, "java/lang/IllegalStateException", NULL);

return;

}

process_media_player_call( env, thiz, mp->reset(), NULL, NULL );

}

先獲取一個MediaPlayer指針,通過對它的調用來實現實際的功能。

register_android_media_MediaPlayer用於將gMethods注冊為的類"android/media/MediaPlayer",其實現如下所示。

static int register_android_media_MediaPlayer(JNIEnv *env)

{

jclass clazz;

clazz = env->FindClass("android/media/MediaPlayer");

// ......

return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));

}

"android/media/MediaPlayer"對應JAVA的類android.media.MediaPlayer。

3.3 libmedia.so

frameworks/base/media/libmedia/mediaplayer.cpp文件實現mediaplayer.h提供的介面,其中一個重要的片段如下所示:

const sp& MediaPlayer::getMediaPlayerService()

{

Mutex::Autolock _l(mServiceLock);

if (mMediaPlayerService.get() == 0) {

sp sm = defaultServiceManager();

sp binder;

do {

binder = sm->getService(String16("media.player"));

if (binder != 0)

break;

LOGW("MediaPlayerService not published, waiting...");

usleep(500000); // 0.5 s

} while(true);

if (mDeathNotifier == NULL) {

mDeathNotifier = new DeathNotifier();

}

binder->linkToDeath(mDeathNotifier);

mMediaPlayerService = interface_cast(binder);

}

LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?");

return mMediaPlayerService;

}

其中最重要的一點是binder =
sm->getService(String16("media.player"));這個調用用來得到一個名稱為"media.player"的服務,這個調用返回值的類型為IBinder,根據實現將其轉換成類型IMediaPlayerService使用。

一個具體的函數setDataSource如下所示:

status_t MediaPlayer::setDataSource(const char *url)

{

LOGV("setDataSource(%s)", url);

status_t err = UNKNOWN_ERROR;

if (url != NULL) {

const sp& service(getMediaPlayerService());

if (service != 0) {

sp player(service->create(getpid(), this, url));

err = setDataSource(player);

}

}

return err;

}

4. 什麼是android的框架開發

Android開發框架介紹
編輯文檔
學分 +2
開發框架方麵包含基本的應用功能開發、數據存儲、網路訪問這三大塊:
一、應用方面
一般而言一個標準的Android程序由如下4部分組成即Activity、Broadcast Intent Receiver、Service、Content Provider: 1. Activity是最頻繁、最基本的模塊,在Android中,一個Activity就是手機上一屏,相當於一個網頁一樣,所不同的是,每個Activity運行結束了,有個返回值,類似一個函數一樣。Android系統會自動記錄從首頁到其他頁面的所有跳轉記錄並且自動將以前的Activity壓入系統堆棧,用戶可以通過編程的方式刪除歷史堆棧中的Activity Instance。
Activity類中主要是跟界面資源文件關聯起來(res/layout目錄下的xml資源,也可以不含任何界面資源),內部包含控制項的顯示設計、界面交互設計、事件的響應設計以及數據處理設計、導航設計等application設計的方方面面。 2. Broadcast Intent Receiver
Intent提供了各種不同Activity進行跳轉的機制,譬如如果從A activity跳轉到B activity,使用Intent來實現如下: Intent in = new Intent(A.this, B.class); startActivity(in);
BroadcastReceiver提供了各種不同的Android應用程序進行進行進程間通訊的機制,譬如當電話呼叫來臨時,可以通過BroadcastReceiver發布廣播消息。對於用戶而言,BroadcastReceiver是不透明的,用戶無法看到這個事件,BroadcastReceiver通過NotificationManager來通知用戶這些事件發生了,它既可以在資源AndroidManifest.xml中注冊,也可以在代碼中通過Context.registerReceiver()進行注冊,只要是注冊了,當事件來臨的時候,即時程序沒有啟動,系統也在需要的時候會自動啟動此應用程序;另外各應用程序很方便地通過Context.sendBroadcast()將自己的事情廣播給其他應用程序;
3. Service,跟Windows當中的Service完全是一個概念,用戶可以通過startService(Intent service)啟動一個Service,也可通過Context.bindService來綁定一個Service.
4. Content Provider,由於Android應用程序內部的數據都是私有的,Content Provider提供了應用程序之間數據交換的機制,一個程序可以通過實現一個ContentProvider的抽象介面將自己的數據暴露出去,並且隱蔽了具體的數據存儲實現,標準的ContentProvider提供了基本的CRUD(Create,Read,Update,Delete)的介面,並且實現了許可權機制,保護了數據交互的安全性; 一個標準的Android應用程序的工程文件包含如下幾大部分: -> Java源代碼部分(包含Activity),都在src目錄當中;
-> R.java文件,這個文件是Eclipse自動生成與維護的,開發者不需要修改,提供了Android對的資源全局索引; -> Android Library,這個是應用運行的Android庫;
-> assets目錄,這個目錄裡面主要用與放置多媒體等一些文件;
-> res目錄,放置的是資源文件,跟VC中的資源目錄基本類似,其中的drawable包含的是圖片文件,layout裡麵包含的是布局文件,values目錄裡面主要包含的是字元串(strings.xml)、顏色(colors.xml)以及數組(arrays.xml)資源;
-> AndroidManifest.xml,這個文件異常重要,是整個應用的配置文件,在這個文件中,需要聲明所有用到的Activity、Service、Receiver等。

5. 學習教學多媒體系統看什麼書

Android憑借其開源性、優異的用戶體驗和極為方便的開發方式,贏得了廣大用戶和開發者的青睞,目前已經發展成為市場佔有率很高的智能手機操作系統。 《Android驅動開發與移植實戰詳解》分為18章,依次講解了Android系統的基本知識, Linux內核的基本知識,分析了Android系統的源碼,深入分析HAL層的基本知識,GoldFish下的驅動、MSM內核和驅動、OMAP內核和驅動、顯示系統驅動、輸入系統驅動、振動器系統驅動、音頻系統驅動和視頻輸出系統驅動,多媒體框架,感測器系統、照相機系統、Wi-Fi系統、藍牙系統、GPS系統和電話系統的知識。在每一章中,重點介紹了與Android驅動開發相關的底層知識,並對Android源碼進行了詳細的分析及驅動開發實現。 《Android驅動開發與移植實戰詳解》適合Android程序員、研發人員及Android愛好者學習,也可以作為相關培訓學校和大專院校相關專業的教學用書。

6. 應聘Android開發工程師,需要掌握哪些專業技能

任職要求:

1.Android/iphone平台手機終端軟體開發精通Android開發平台及框架,一年以上實際開發經驗;

2.精通Android GUI程序開發;

3.1年以上J2ME開發經驗,熟悉J2ME編程;熟悉Linux環境編程優先 ;從事過嵌入式開發工作2年以上。

4.熟悉HTML/WML/HTTP,具有良好的編程思想;

5.熟悉C/C++或者Java開發語言和環境;

6.有一年以上移動終端應用軟體開發經驗,有Android或者iPhone開發經驗尤佳;

7.基礎扎實,精通常用數據結構與演算法和設計能力;

8.熟悉移動終端特性和開發特點; 熟悉移動終端網路編程,了解3G\WiFi等技術;

9.熟悉C++/C#, MSSQL/MySQL資料庫開發;熟悉多線程、Socket或ACE等網路通信編程技術;

10.熟悉java各種編程方法,比如多線程,jni,idl等。 熟悉JVM的運行機制,移植或者擴展過JVM到嵌入式平台者優先,比如phoneme 等。

11.精通Android平台UI開發優先;英語良好,能閱讀英文資料;

工作職責:

1.負責Android平台的瀏覽器開發。

2.在Android手機上設計並開發應用程序或游戲;

3.Android平台框架層的維護以及擴展。

4.移植各種流行的框架體系(多媒體,藍牙,無線)到android上負責Android項目的開發工作;

5.負責Android項目的架構設計、方案的制定;

6.跟進Android的新技術發展。纂寫設計開發及實現文檔;

7.根據產品功能需求設計並完成軟體實現;

8.參與產品需求分析並制定技術實施方案;

7. 程序包io.vov.vitamio.utils 怎麼引入

二、 簡介
Vitamio 是一款 Android 平台上的全能多媒體開發框架。Vitamio 憑借其簡潔易用的 API 介面贏得了全球眾多開發者的青睞。到目前,全球已經有超過 1000 種應用在使用 Vitamio,覆蓋用戶超過 5000 萬。
Vitamio 能夠流暢播放720P甚至1080P高清MKV,FLV,MP4,MOV,TS,RMVB等常見格式的視頻,還可以在 Android 上支持 MMS, RTSP, RTMP, HLS(m3u8) 等常見的多種視頻流媒體協議,包括點播與直播。
支持 ARMv6 和 ARMv7 兩種 ARM CPU,同時對 VFP, VFPv3, NEON 等指令集都做相應優化。
支持 Android 2.1+ 系統,支持超過 95% 的 Android 市場。同時 Android 2.1 之前的系統也基本支持,不過沒做詳細測試。
其他Vitamio的介紹參照這里。

三、使用
1、導入。下載回來後大家可能發現沒有.project工程文件,可以通過File -> Import -> Android -> Existing Android Code Into Workspace來導入工程,然後改一下工程名稱即可。
2、將VitamioBundle工程作為Android Library引入Demo工程使用即可。
新手無法解決這些問題建議直接使用上面的鏈接,導入工程即可使用。

8. 安卓Android軟體開發用什麼語言

Android以Java為編程語言。

操作系統與應用程序的溝通橋梁,並用分為兩層:函數層(Library)和虛擬機(Virtual Machine)。 Bionic是 Android 改良libc的版本。

Android 同時包含了Webkit,所謂的Webkit 就是Apple Safari瀏覽器背後的引擎。Surface flinger 是就2D或3D的內容顯示到屏幕上。Android使用工具鏈(Toolchain)為Google自製的Bionic Libc。

Android採用OpenCORE作為基礎多媒體框架。OpenCORE可分7大塊:PVPlayer、PVAuthor、Codec、PacketVideo Multimedia Framework(PVMF)、Operating System Compatibility Library(OSCL)、Common、OpenMAX。

(8)android多媒體框架擴展閱讀:

安卓軟體開發學習內容

Android基礎階段:平台架構特性(JAVA/C) Market/應用程序組件 環境搭建與部署/打包與發布 AVD/DDMS/AAPT 調試與測試 相關資源訪問/資源製作 。

Activity/Service/Broadcast Receiver/Content Provider/原理(生命周期)及深層實現。

Android進階初級:組件Widget/ 菜單Menu/ 布局Layout 詳解 Xml解析(Pull/Dom/Sax)/JNI 解析SQL資料庫原理, SQLite /SharedPreferences/File詳解 多媒體Audio/Video/Camera 詳解。

Android進階高級:藍牙/WIFI SMS/MMS 應用實現 深層次解析GPS原理,實現。LocationManager/LocationProvider 進行定位/跟蹤/查找/趨近警告以及Geocoder正逆向編解碼等技術細節。

2D圖形庫(Graphics/View)詳解 SDCARD/感測器/手勢 應用實現。

9. android框架師和androidframework工程師的區別

高級Android多媒體工程師

1.負責Android系統多媒體業務特性的需求分析、總體設計及關鍵模塊開發實現及調試定位;
2、負責攻關解決Android AudioSystem/OpenGL/圖形系統/多媒體並發等android系統級多媒體問題;

1. 具有2年以上Android多媒體系統問題解決經驗;
2. 熟悉AudioSystem/OpenGL/SurfaceFlinger等具體多媒體技術

高級Android Framework工程師

1.負責Android系統Framework及內核等系統框架層的需求優化分析、優化設計及關鍵模塊開發實現及調試定位

1.3年以上嵌入式系統 2.精通C/C++

高級Android瀏覽器工程師

1. 負責Android系統瀏覽器等移動互聯業務特性的需求分析、總體設計及關鍵模塊開發實現及調試定位;
2. 負責攻關解決Android Webkit問題及進行瀏覽器性能優化

1. 具有2年以上Android瀏覽器系統問題解決經驗;
2. 熟悉Webkit系統架構及問題定位方法;
3. 熟悉javascript/css等具體技術

ANDROID高級驅動軟體工程師

1、 ANDROID MediaFramework、HAL、 KERNEL中關鍵系統、關鍵外設的開發、軟體優化;
2、 負責ANDROIID關鍵技術問題的公關,性能優化等技術工作;
3、 協助培養、管理ANDIROID底層軟體開發團隊

1. 4年以上LINUX嵌入式驅動軟體開發經驗,以及3年以上Android手機底層軟體開發經驗
2. 有過在晶元裸板上面進行從零開始的Linux(Android)移植工作經驗;
3. 精通LINUX內核,具備多核處理器整機功耗優化的處理經驗,具備基於多核的內核異常問題處理經驗和有效手段;
4. 在Android系統下,有豐富的外設開發經驗,並熟悉音視頻多媒體框架

10. android中mediamuxer和mediacodec的區別

Android中MediaMuxer和MediaCodec用例
在Android的多媒體類中,MediaMuxer和MediaCodec算是比較年輕的,它們是JB 4.1和JB 4.3才引入的。前者用於將音頻和視頻進行混合生成多媒體文件。缺點是目前只能支持一個audio track和一個video track,而且僅支持mp4輸出。不過既然是新生事物,相信之後的版本應該會有大的改進。MediaCodec用於將音視頻進行壓縮編碼,它有個比較牛X的地方是可以對Surface內容進行編碼,如KK 4.4中屏幕錄像功能就是用它實現的。

注意它們和其它一些多媒體相關類的關系和區別:MediaExtractor用於音視頻分路,和MediaMuxer正好是反過程。MediaFormat用於描述多媒體數據的格式。MediaRecorder用於錄像+壓縮編碼,生成編碼好的文件如mp4, 3gpp,視頻主要是用於錄制Camera preview。MediaPlayer用於播放壓縮編碼後的音視頻文件。AudioRecord用於錄制PCM數據。AudioTrack用於播放PCM數據。PCM即原始音頻采樣數據,可以用如vlc播放器播放。當然了,通道采樣率之類的要自己設,因為原始采樣數據是沒有文件頭的,如:
vlc --demux=rawaud --rawaud-channels 2 --rawaud-samplerate 44100 audio.pcm

回到MediaMuxer和MediaCodec這兩個類,它們的參考文檔見http://developer.android.com/reference/android/media/MediaMuxer.html和http://developer.android.com/reference/android/media/MediaCodec.html,里邊有使用的框架。這個組合可以實現很多功能,比如音視頻文件的編輯(結合MediaExtractor),用OpenGL繪制Surface並生成mp4文件,屏幕錄像以及類似Camera app里的錄像功能(雖然這個用MediaRecorder更合適)等。

這里以一個很無聊的功能為例,就是在一個Surface上畫圖編碼生成視頻,同時用MIC錄音編碼生成音頻,然後將音視頻混合生成mp4文件。程序本身沒什麼用,但是示例了MediaMuxer和MediaCodec的基本用法。本程序主要是基於兩個測試程序:一個是Grafika中的SoftInputSurfaceActivity和HWEncoderExperiments。它們一個是生成視頻,一個生成音頻,這里把它們結合一下,同時生成音頻和視頻。基本框架和流程如下:

首先是錄音線程,主要參考HWEncoderExperiments。通過AudioRecord類接收來自麥克風的采樣數據,然後丟給Encoder准備編碼:

AudioRecord audio_recorder;
audio_recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, buffer_size);
// ...
audio_recorder.startRecording();
while (is_recording) {
byte[] this_buffer = new byte[frame_buffer_size];
read_result = audio_recorder.read(this_buffer, 0, frame_buffer_size); // read audio raw data
// …
presentationTimeStamp = System.nanoTime() / 1000;
audioEncoder.offerAudioEncoder(this_buffer.clone(), presentationTimeStamp); // feed to audio encoder

}

這里也可以設置AudioRecord的回調(通過())來觸發音頻數據的讀取。offerAudioEncoder()里主要是把audio采樣數據送入音頻MediaCodec的InputBuffer進行編碼:

ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(this_buffer);
...
mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, this_buffer.length, presentationTimeStamp, 0);
}

下面,參考Grafika-SoftInputSurfaceActivity,並加入音頻處理。主循環大體分四部分:

try {
// Part 1
prepareEncoder(outputFile);
...
// Part 2
for (int i = 0; i < NUM_FRAMES; i++) {
generateFrame(i);
drainVideoEncoder(false);
drainAudioEncoder(false);
}
// Part 3
...
drainVideoEncoder(true);
drainAudioEncoder(true);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} finally {
// Part 4
releaseEncoder();
}

第1部分是准備工作,除了video的MediaCodec,這里還初始化了audio的MediaCodec:

MediaFormat audioFormat = new MediaFormat();
audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
...
mAudioEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
mAudioEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mAudioEncoder.start();

第2部分進入主循環,app在Surface上直接繪圖,由於這個Surface是從MediaCodec中用createInputSurface()申請來的,所以畫完後不用顯式用queueInputBuffer()交給Encoder。drainVideoEncoder()和drainAudioEncoder()分別將編碼好的音視頻從buffer中拿出來(通過dequeueOutputBuffer()),然後交由MediaMuxer進行混合(通過writeSampleData())。注意音視頻通過PTS(Presentation time stamp,決定了某一幀的音視頻數據何時顯示或播放)來同步,音頻的time stamp需在AudioRecord從MIC採集到數據時獲取並放到相應的bufferInfo中,視頻由於是在Surface上畫,因此直接用dequeueOutputBuffer()出來的bufferInfo中的就行,最後將編碼好的數據送去MediaMuxer進行多路混合。

注意這里Muxer要等把audio track和video track都加入了再開始。MediaCodec在一開始調用dequeueOutputBuffer()時會返回一次INFO_OUTPUT_FORMAT_CHANGED消息。我們只需在這里獲取該MediaCodec的format,並注冊到MediaMuxer里。接著判斷當前audio track和video track是否都已就緒,如果是的話就啟動Muxer。

總結來說,drainVideoEncoder()的主邏輯大致如下,drainAudioEncoder也是類似的,只是把video的MediaCodec換成audio的MediaCodec即可。
while(true) {
int encoderStatus = mVideoEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
...
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
encoderOutputBuffers = mVideoEncoder.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = mAudioEncoder.getOutputFormat();
mAudioTrackIndex = mMuxer.addTrack(newFormat);
mNumTracksAdded++;
if (mNumTracksAdded == TOTAL_NUM_TRACKS) {
mMuxer.start();
}
} else if (encoderStatus < 0) {
...
} else {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
...
if (mBufferInfo.size != 0) {
mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
}
mVideoEncoder.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
break;
}
}

}

第3部分是結束錄制,發送EOS信息,這樣在drainVideoEncoder()和drainAudioEncoder中就可以根據EOS退出內循環。第4部分為清理工作。把audio和video的MediaCodec,MediaCodec用的Surface及MediaMuxer對象釋放。

最後幾點注意:
1. 在AndroidManifest.xml里加上錄音許可權,否則創建AudioRecord對象時鐵定失敗:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
2. 音視頻通過PTS同步,兩個的單位要一致。
3. MediaMuxer的使用要按照Constructor -> addTrack -> start -> writeSampleData -> stop 的順序。如果既有音頻又有視頻,在stop前兩個都要writeSampleData()過。

Code references:
Grafika: https://github.com/google/grafika
Bigflake: http://bigflake.com/mediacodec/
HWEncoderExperiments:https://github.com/OnlyInAmerica/HWEncoderExperiments/tree/audioonly/HWEncoderExperiments/src/main/java/net/openwatch/hwencoderexperiments
Android test:http://androidxref.com/4.4.2_r2/xref/cts/tests/tests/media/src/android/media/cts/
http://androidxref.com/4.4.2_r2/xref/pdk/apps/TestingCamera2/src/com/android/testingcamera2/CameraRecordingStream.java

閱讀全文

與android多媒體框架相關的資料

熱點內容
考駕照怎麼找伺服器 瀏覽:882
阿里雲伺服器如何更換地區 瀏覽:970
手機app調音器怎麼調古箏 瀏覽:501
銳起無盤系統在伺服器上需要設置什麼嗎 瀏覽:17
紅旗計程車app怎麼應聘 瀏覽:978
如何編寫linux程序 瀏覽:870
吉利車解壓 瀏覽:248
java輸入流字元串 瀏覽:341
安卓軟體沒網怎麼回事 瀏覽:785
dvd壓縮碟怎麼導出電腦 瀏覽:274
冒險島什麼伺服器好玩 瀏覽:541
如何在伺服器上做性能測試 瀏覽:793
命令序列錯 瀏覽:259
javaif的條件表達式 瀏覽:576
手機app上傳的照片怎麼找 瀏覽:531
雲伺服器面臨哪些威脅 瀏覽:748
c語言各種編譯特點 瀏覽:177
路由器多種加密方法 瀏覽:604
程序員阻止電腦自動彈出定位 瀏覽:168
如何做伺服器服務商 瀏覽:763