『壹』 android下視頻文件從解碼到播放需要哪幾步,請簡述
Android通過軟解碼播放視頻
1, 一般情況下Android的平台都是硬解碼視頻的,尤其是在Arm平台這種成熟的硬體平台上面(硬解碼代碼由晶元廠商提供)。但是Android移植到
2, MIPS平台時間還不長,還不成熟,還需要自己實現硬體解碼的工作。為了早日讓Android在MIPS平台運行起來,我選擇了先用軟解碼播放視頻。
3,Android代碼是從Android on MIPS社區獲得的代碼。發現軟解碼視頻播放過程中會發生崩潰。經過分析好像是內存分配的問題。
4, 經過研究OpenCore庫(Android框架是通過OpenCore來播放視頻的,網上有很多關於OpenCore的介紹,這里就不多說了),並參考Android平台——Surfaceflinger機制。發現問題出在源文件:
frameworks/base/libs/surfaceflinger/LayerBuffer.cpp的LayerBuffer::BufferSource::postBuffer方法中:
............
buffer = new LayerBuffer::Buffer(buffers, offset);
............類LayerBuffer::Buffer的構造函數代碼如下:
LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
: mBufferHeap(buffers)
{
NativeBuffer& src(mNativeBuffer);
g.handle = 0;
gralloc_mole_t const * mole = LayerBuffer::getGrallocMole();
if (mole && mole->perform) {
int err = mole->perform(mole,
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
buffers.heap->heapID(), buffers.heap->getSize(),
offset, buffers.heap->base(),
& g.handle);
if (err == NO_ERROR) {
op.l = 0;
op.t = 0;
op.r = buffers.w;
op.b = buffers.h;
g.w = buffers.hor_stride ?: buffers.w;
g.h = r_stride ?: buffers.h;
rmat = rmat;
se = (void*)(intptr_t(buffers.heap->base()) + offset);
}
}
}LayerBuffer::getGrallocMole方法的調用到的Gralloc為:
hardware/libhardware/moles/gralloc/gralloc.cpp因為的沒有實現在自己的硬體只能用通用的Gralloc,經過分析發現通用的Gralloc沒有實現
5, mole->perform函數指針,mole->perform為NULL,所以不會對Buffer進行必要的初始化(我覺得應該是一個疏忽,只是不知道是谷歌的疏忽,還是MIPS移植人員的疏忽,最起碼應該能夠讓通用硬體能跑起來)。參考其他的硬體實現一個perform函數指針到通用Gralloc中。
在源文件:
hardware/libhardware/moles/gralloc/mapper.cpp增加如下的函數定義:
int gralloc_perform(struct gralloc_mole_t const* mole,
int operation, ... )
{
int res = -EINVAL;
va_list args;
va_start(args, operation);
switch (operation) {
case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: {
int fd = va_arg(args, int);
size_t size = va_arg(args, size_t);
size_t offset = va_arg(args, size_t);
void* base = va_arg(args, void*);
native_handle_t** handle = va_arg(args, native_handle_t**);
private_handle_t* hnd = (private_handle_t*)native_handle_create(
private_handle_t::sNumFds, private_handle_t::sNumInts);
hnd->magic = private_handle_t::sMagic;
hnd->fd = fd;
hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM;
hnd->size = size;
hnd->offset = offset;
hnd->base = intptr_t(base) + offset;
hnd->lockState = private_handle_t::LOCK_STATE_MAPPED;
*handle = (native_handle_t *)hnd;
res = 0;
break;
}
}
va_end(args);
return res;
}然後在gralloc.cpp中增加,gralloc_perform的聲明:
extern int gralloc_perform(struct gralloc_mole_t const* mole,
int operation, ... );並修改HAL_MODULE_INFO_SYM的定義,增加perform欄位的定義:
struct private_mole_t HAL_MODULE_INFO_SYM = {
base: {
.......
perform: gralloc_perform,
},
......
}; 重新編譯gralloc模塊,再次用Gallary應用程序通過軟解碼播放視頻,就可以流暢的播放了,軟解碼的效率挺高的,沒有卡的感覺!
『貳』 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;
}
『叄』 android mediaplayer 原生支持哪些 視頻 編解碼格式高分急求
『肆』 android mediacodec有什麼方法
Android 用MediaCodec實現視頻硬解碼
本文向你講述如何用android標準的API (MediaCodec)實現視頻的硬體編解碼。常式將從攝像頭採集視頻開始,然後進行H264編碼,再解碼,然後顯示。我將盡量講得簡短而清晰,不展示那些不相關的代碼。但是,我不建議你讀這篇文章,也不建議你開發這類應用,而應該轉而開發一些戳魚、打鳥、其樂融融的程序。好吧,下面的內容是寫給那些執迷不悟的人的,看完之後也許你會同意我的說法:Android只是一個玩具,很難指望它來做靠譜的應用。
1、從攝像頭採集視頻
可以通過攝像頭Preview的回調,來獲取視頻數據。
首先創建攝像頭,並設置參數:
[java] view plain
cam = Camera.open();
cam.setPreviewDisplay(holder);
Camera.Parameters parameters = cam.getParameters();
parameters.setFlashMode("off"); // 無閃光燈
parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setPreviewFormat(ImageFormat.YV12);
parameters.setPictureSize(camWidth, camHeight);
parameters.setPreviewSize(camWidth, camHeight);
//這兩個屬性 如果這兩個屬性設置的和真實手機的不一樣時,就會報錯
cam.setParameters(parameters);
寬度和高度必須是攝像頭支持的尺寸,否則會報錯。要獲得所有支持的尺寸,可用getSupportedPreviewSizes,這里不再累述。據說所有的參數必須設全,漏掉一個就可能報錯,不過只是據說,我只設了幾個屬性也沒出錯。 然後就開始Preview了:
[java] view plain
buf = new byte[camWidth * camHeight * 3 / 2];
cam.addCallbackBuffer(buf);
cam.setPreviewCallbackWithBuffer(this);
cam.startPreview();
setPreviewCallbackWithBuffer是很有必要的,不然每次回調系統都重新分配緩沖區,效率會很低。
在onPreviewFrame中就可以獲得原始的圖片了(當然,this 肯定要 implements PreviewCallback了)。這里我們是把它傳給編碼器:
[java] view plain
public void onPreviewFrame(byte[] data, Camera camera) {
if (frameListener != null) {
frameListener.onFrame(data, 0, data.length, 0);
}
cam.addCallbackBuffer(buf);
}
2、編碼
首先要初始化編碼器:
[java] view plain
mediaCodec = MediaCodec.createEncoderByType("Video/AVC");
MediaFormat mediaFormat = MediaFormat.createVideoFormat(type, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
然後就是給他喂數據了,這里的數據是來自攝像頭的:
[java] view plain
public void onFrame(byte[] buf, int offset, int length, int flag) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0)
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
if (frameListener != null)
frameListener.onFrame(outputBuffer, 0, length, flag);
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
先把來自攝像頭的數據喂給它,然後從它裡面取壓縮好的數據喂給解碼器。
3、解碼和顯示
首先初始化解碼器:
[java] view plain
mediaCodec = MediaCodec.createDecoderByType("Video/AVC");
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mime, width, height);
mediaCodec.configure(mediaFormat, surface, null, 0);
mediaCodec.start();
這里通過給解碼器一個surface,解碼器就能直接顯示畫面。
然後就是處理數據了:
[java] view plain
public void onFrame(byte[] buf, int offset, int length, int flag) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount * 1000000 / FRAME_RATE, 0);
mCount++;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
queueInputBuffer第三個參數是時間戳,其實怎麼寫都無所謂,只要是按時間線性增加的就可以,這里就隨便弄一個了。後面一段的代碼就是把緩沖區給釋放掉,因為我們直接讓解碼器顯示,就不需要解碼出來的數據了,但是必須要這么釋放一下,否則解碼器始終給你留著,內存就該不夠用了。
好了,到現在,基本上就可以了。如果你運氣夠好,現在就能看到視頻了,比如在我的三星手機上這樣就可以了。但是,我試過幾個其他平台,多數都不可以,總是有各種各樣的問題,如果要開發一個不依賴平台的應用,還有很多的問題要解決。說說我遇到的一些情況:
1、視頻尺寸
一般都能支持176X144/352X288這種尺寸,但是大一些的,640X480就有很多機子不行了,至於為什麼,我也不知道。當然,這個尺寸必須和攝像頭預覽的尺寸一致,預覽的尺寸可以枚舉一下。
2、顏色空間
根據ANdroid SDK文檔,確保所有硬體平台都支持的顏色,在攝像頭預覽輸出是YUV12,在編碼器輸入是COLOR_FormatYUV420Planar,也就是前面代碼中設置的那樣。 不過,文檔終究是文檔,否則安卓就不是安卓。
在有的平台上,這兩個顏色格式是一樣的,攝像頭的輸出可以直接作為編碼器的輸入。也有的平台,兩個是不一樣的,前者就是YUV12,後者等於I420,需要把前者的UV分量顛倒一下。下面的代碼效率不高,可供參考。
[java] view plain
byte[] i420bytes = null;
private byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
if (i420bytes == null)
i420bytes = new byte[yv12bytes.length];
for (int i = 0; i < width*height; i++)
i420bytes[i] = yv12bytes[i];
for (int i = width*height; i < width*height + (width/2*height/2); i++)
i420bytes[i] = yv12bytes[i + (width/2*height/2)];
for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
i420bytes[i] = yv12bytes[i - (width/2*height/2)];
return i420bytes;
}
這里的困難是,我不知道怎樣去判斷是否需要這個轉換。據說,Android 4.3不用再從攝像頭的PreView裡面取圖像,避開了這個問題。這里有個例子,雖然我沒讀,但看起來挺厲害的樣子,應該不會有錯吧(覺厲應然)。http://bigflake.com/mediacodec/CameraToMpegTest.java.txt
3、輸入輸出緩沖區的格式
SDK里並沒有規定格式,但是,這種情況H264的格式基本上就是附錄B。但是,也有比較有特色的,它就是不帶那個StartCode,就是那個0x000001,搞得把他編碼器編出來的東西送給他的解碼器,他自己都解不出來。還好,我們可以自己加。
[java] view plain
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size + 3];
outputBuffer.get(outData, 3, bufferInfo.size);
if (frameListener != null) {
if ((outData[3]==0 && outData[4]==0 && outData[5]==1)
|| (outData[3]==0 && outData[4]==0 && outData[5]==0 && outData[6]==1))
{
frameListener.onFrame(outData, 3, outData.length-3, bufferInfo.flags);
}
else
{
outData[0] = 0;
outData[1] = 0;
outData[2] = 1;
frameListener.onFrame(outData, 0, outData.length, bufferInfo.flags);
}
}
4、有時候會死在dequeueInputBuffer(-1)上面
根據SDK文檔,dequeueInputBuffer 的參數表示等待的時間(毫秒),-1表示一直等,0表示不等。按常理傳-1就行,但實際上在很多機子上會掛掉,沒辦法,還是傳0吧,丟幀總比掛掉好。當然也可以傳一個具體的毫秒數,不過沒什麼大意思吧。
『伍』 安卓開發怎麼將和h264文件解碼播放
如題所示,我想將攝像頭採集的數據進行h.264硬編碼,我想知道Android是如何對視頻數據進行硬體編碼的
目前已經知道的方案有:
1、用Android4.1 API MediaCodec來對視頻數據進行編碼
http://stackoverflow.com/q/17232477/2293921
此種方式我測試了,並未成功,目前一直卡在這里,如果你等幫助我,我將非常感激
2、通過MediaRecorder方式對數據進行編碼
具體可參考 http://blog.csdn.net/zblue78/article/details/6083374
3、通過移植ffmpeg
這種方式沒接觸過,也不了解
可能還有一些其他的方式來對視頻硬編碼,如果你了解一下,感謝分享!
綜上,我更傾向於1的方式去做
我來回答
Android , MediaCodec , 硬編碼
post_newreply
//$(\'note_\').focus();
function succeedhandle_vfastpost(url, message, param) {
$(\'vmessage\').value = \'\';
succeedhandle_fastpost(url, message, param);
showCreditPrompt();
}
var vf_tips = \'#在這里快速回復#\';
$(\'vmessage\').value = vf_tips;
$(\'vmessage\').style.color = \'#CDCDCD\';
$(\'vmessage\').onclick = function() {
if($(\'vmessage\').value==vf_tips) {
$(\'vmessage\').value=\'\';
$(\'vmessage\').style.color=\"#000\";
}
}
$(\'vmessage\').onblur = function() {
if(!$(\'vmessage\').value) {
$(\'vmessage\').value=vf_tips;
$(\'vmessage\').style.color=\"#CDCDCD\";
}
}
$(\'vreplysubmit\').onclick = function() {
if($(\'vmessage\').value == vf_tips) {
return false;
}
}
『陸』 安卓視頻解碼器,這個安卓視頻解碼器的原理是什麼安卓解碼器一般在apk的哪個文件
據我所了解的,MX Player這款安卓影音播放器可以在安裝軟體之後搭配使用解碼器,硬體解碼和軟體解碼可以相互彌補不足。解碼的原理,簡單的理解就是解碼器識別影音文件的編碼方式,然後將其內部代碼編譯成手機硬體可識別並能表現出來的二進制代碼。亦可理解成解碼器認識出來影音文件,然後介紹給手機硬體,最終手機屏幕展現出能被人們看到的圖像和聲音。
安卓解碼器一般在apk的那個文件?這句話不明白你要表達什麼意思。apk是一個已經編譯好的安卓手機軟體格式,內部也是無數代碼組成的。
『柒』 在Android系統中如何調用系統自帶的視頻解碼器
對需要用FF解碼的視頻類型去掉內部解碼勾選
2.在外部解碼器中對所選視頻選擇FF解碼器即可
『捌』 android vlc怎麼硬解碼
前幾天用PC平台上的VLC播放RTSP流媒體時延遲時間較長,存在1s左右的延遲,效果不是很好,後來查了資料,發現這個延遲時間是可以修改的。 找到工具->首選項,然後參數設置左下角選擇「全部」,左邊選擇 「輸入編解碼」->「網路緩存」選項,可以根據具體需要加以修改,具體見下圖不過這個值不要太小,否則緩存太小,播放視頻的過程中會很卡
『玖』 android 區域網實時語音聊天音頻流用什麼編
一般如果應用需要進行大量數學運算時,推薦使用JNI在Java中調用C/C++編寫的動態庫,Java只負責邏輯和界面用戶操作的相應,
你這個APP很簡單分為以下幾個模塊
界面,與用戶進行交互,需要具備Android界面的編程;
網路傳輸,需要掌握Java網路socket編程的知識,使用TCP傳輸編碼後的音頻幀;
語音編解碼模塊,由兩部分構成。一是c/c++編寫的動態庫,二是Java聲明本地native函數,並將c/c++實現的native函數進行封裝,方便Java調用。這部分需要掌握Java中JNI使用的知識,c/c++編程,語音處理的方面的知識,例如數字信號處理。
而c/c++寫的庫一般不是我們自己實現的,而是引入第三方開源代碼,這里的選擇有很多,我了解到的有
ffmeg,很常用,就連暴風影音和QQ音樂據說用了他們的開源庫,而沒有遵守開源協議而進入了他們的黑名單。
speex,是國外的開源庫,現已被Opus取代,但是speex多了一個預處理功能,例如降噪、自動增益、迴音消除等等。
Superpowered,跨平台的,低延遲,功能多。
補充一點,Android現已支持純C++的開發了,這個就需要NDK的配合,寫出NativeActivity,然後就可以直接在C++中調用第三方的庫了,而不用JNI這樣繁瑣,但是由於剛出來,教程不多,需要具備很多嵌入式、音視頻採集處理的開發經驗。
『拾』 音頻播放需要用到編解碼技術嗎 android
1、android提供的音視頻編碼只有 AMR-NB(nb是窄頻)和H.263
2、android雖然支持gif的解碼,只能用mediaplay來播放,但是效果不好
3、android不支持flv的解碼
4、AudioTrack只能播放pcm編碼的數據,MediaPlayer可以播放MP3,AAC,WAV,OGG,MIDI等
事實上,兩種本質上是沒啥區別的,MediaPlayer在播放音頻時,在framework層還是會創建AudioTrack,
把解碼後的PCM數據傳遞給AudioTrack,最後由AudioFlinger進行混音,傳遞音頻給硬體播放出來。
利用AudioTrack播放只是跳過 Mediaplayer的解碼部分而已。Mediaplayer的解碼核心部分是基於OpenCORE 來實現的,
支持通用的音視頻和圖像格式,codec使用的是OpenMAX介面來進行擴展。因此使用audiotrack播放mp3文件的話,要自己加入 一個音頻解碼器,如libmad。
否則只能播放PCM數據,如大多數WAV格式的音頻文件。