‘壹’ 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格式的音频文件。