您的位置:首页 > 移动开发 > Android开发

关于havlenapetr-FFMpeg在Android 4.0(ICS)的补充说明

2012-11-04 00:56 513 查看
/********************************************************************************************

* author:conowen@大钟

* E-mail:conowen@hotmail.com

* http://blog.csdn.net/conowen

* 注:本文为原创,仅作为学习交流使用,转载请标明作者及出处。

********************************************************************************************/

之前的这篇博文/article/1415899.html

所提及到的framework/base/native文件夹下面的audio与vedio文件夹可以在https://github.com/havlenapetr/android_frameworks_base

然而,对于Android 4.0(ICS),上述的地址中的ICS分支对于原本的FFmpeg工程显然是不能对接得上的,虽然可以在Android 4.0 的source code中编译通过,但是这个分支的surface.cpp中定义的方法与FFmpeg的JNI方法对应不上。

@Android 4.0 ICS的surface.cpp

[java] view
plaincopy

/*

* Copyright (C) 2012 Havlena Petr

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/



#define LOG_TAG "ASurface"

#include <utils/Log.h>



#include <surfaceflinger/Surface.h>



#include <SkCanvas.h>

#include <SkBitmap.h>

#include <SkMatrix.h>

#include <SkRect.h>



#include "surface.h"



#define CHECK(val) \

if(!val) { \

LOGE("%s [%i]: NULL pointer exception!", __func__, __LINE__); \

return -1; \

}



#define SDK_VERSION_FROYO 8



using namespace android;



typedef struct ASurface {

/* our private members here */

Surface* surface;

SkCanvas canvas;

} ASurface;



static Surface* getNativeSurface(JNIEnv* env, jobject jsurface, int sdkVersion) {

/* we know jsurface is a valid local ref, so use it */

jclass clazz = env->GetObjectClass(jsurface);

if(clazz == NULL) {

LOGE("Can't find surface class!");

return NULL;

}



jfieldID field_surface = env->GetFieldID(clazz,

sdkVersion > SDK_VERSION_FROYO ? "mNativeSurface" : "mSurface",

"I");

if(field_surface == NULL) {

LOGE("Can't find native surface field!");

return NULL;

}

return (Surface *) env->GetIntField(jsurface, field_surface);

}



int ASurface_init(JNIEnv* env, jobject jsurface, int sdkVersion, ASurface** aSurface) {

if(!env || jsurface == NULL) {

LOGE("JNIEnv or jsurface obj is NULL!");

return -1;

}



Surface* surface = getNativeSurface(env, jsurface, sdkVersion);

if(!surface) {

LOGE("Can't obtain native surface!");

return -1;

}



*aSurface = (ASurface *) malloc(sizeof(ASurface));

(*aSurface)->surface = surface;

return 0;

}



void ASurface_deinit(ASurface** aSurface) {

free(*aSurface);

*aSurface = NULL;

}



int ASurface_lock(ASurface* aSurface, AndroidSurfaceInfo* info) {

static Surface::SurfaceInfo surfaceInfo;



CHECK(aSurface);

CHECK(aSurface->surface);



Surface* surface = aSurface->surface;

if (!surface->isValid()) {

LOGE("Native surface isn't valid!");

return -1;

}



int res = surface->lock(&surfaceInfo);

if(res < 0) {

LOGE("Can't lock native surface!");

return res;

}



info->w = surfaceInfo.w;

info->h = surfaceInfo.h;

info->s = surfaceInfo.s;

info->usage = surfaceInfo.usage;

info->format = surfaceInfo.format;

info->bits = surfaceInfo.bits;



return 0;

}



static SkBitmap::Config

convertPixelFormat(APixelFormat format) {

switch(format) {

case ANDROID_PIXEL_FORMAT_RGBX_8888:

case ANDROID_PIXEL_FORMAT_RGBA_8888:

return SkBitmap::kARGB_8888_Config;

case ANDROID_PIXEL_FORMAT_RGB_565:

return SkBitmap::kRGB_565_Config;

}

return SkBitmap::kNo_Config;

}



static void

initBitmap(SkBitmap& bitmap, AndroidSurfaceInfo* info) {

bitmap.setConfig(convertPixelFormat(info->format), info->w, info->h);

if (info->format == ANDROID_PIXEL_FORMAT_RGBX_8888) {

bitmap.setIsOpaque(true);

}

if (info->w > 0 && info->h > 0) {

bitmap.setPixels(info->bits);

} else {

// be safe with an empty bitmap.

bitmap.setPixels(NULL);

}

}



void ASurface_scaleToFullScreen(ASurface* aSurface, AndroidSurfaceInfo* src, AndroidSurfaceInfo* dst) {

SkBitmap srcBitmap;

SkBitmap dstBitmap;

SkMatrix matrix;



initBitmap(srcBitmap, src);

initBitmap(dstBitmap, dst);

matrix.setRectToRect(SkRect::MakeWH(srcBitmap.width(), srcBitmap.height()),

SkRect::MakeWH(dstBitmap.width(), dstBitmap.height()),

SkMatrix::kFill_ScaleToFit);



aSurface->canvas.setBitmapDevice(dstBitmap);

aSurface->canvas.drawBitmapMatrix(srcBitmap, matrix);

}



int ASurface_rotate(ASurface* aSurface, AndroidSurfaceInfo* src, uint32_t degrees) {

SkBitmap bitmap;



CHECK(aSurface);

CHECK(src);



initBitmap(bitmap, src);

aSurface->canvas.setBitmapDevice(bitmap);

return aSurface->canvas.rotate(SkScalar(degrees)) ? 0 : -1;

}



int ASurface_unlockAndPost(ASurface* aSurface) {

CHECK(aSurface);

CHECK(aSurface->surface);

return aSurface->surface->unlockAndPost();

}

@Z:\projects\ffmpeg\jni\libmediaplayer\output.cpp(视频输出接口部分)

[java] view
plaincopy

//-------------------- Video driver --------------------

//这四个接口都没有在surface.cpp里面定义



int Output::VideoDriver_register(JNIEnv* env, jobject jsurface)

{

return AndroidSurface_register(env, jsurface);

}



int Output::VideoDriver_unregister()

{

return AndroidSurface_unregister();

}



int Output::VideoDriver_getPixels(int width, int height, void** pixels)

{

return AndroidSurface_getPixels(width, height, pixels);

}



int Output::VideoDriver_updateSurface()

{

return AndroidSurface_updateSurface();

}

但是,我们依然可以把Android 2.3 (Gingerbread)中的video模块一样地移植到Android 4.0(ICS)中去,因为这个分支的surface.cpp的方法依然可以和JNI对接上。

编译步骤可以参考之前的博文,这里不再赘述。

但是在ICS的机器上面运行此播放器时,可能会提示以下errors。(Surface::lock failed, already locked)

[java] view
plaincopy

08-16 21:46:41.863: E/FFMpegMediaPlayer(2263): waiting on video thread

08-16 21:46:41.873: I/FFMpegVideoDecoder(2263): videoclock----> 6.680000

08-16 21:46:41.883: E/SurfaceTextureClient(2263): Surface::lock failed, already locked

08-16 21:46:41.893: I/FFMpegVideoDecoder(2263): videoclock----> 6.720000

08-16 21:46:41.913: E/SurfaceTextureClient(2263): Surface::lock failed, already locked

这和机器的ROM有关系。因为Android 4.0(ICS)中的libsurfaceflinger.so库没有具体的内容,视频输出有关的surface操作函数由libgui.so完成。而有些SDK对gui库进行改动了。所以把Google官方源码包中的framework/base/libs/gui文件夹和framework/base/include/gui文件夹面的gui库代替机器的SDK中的gui包,重新编译生成ROM,即可正常播放。

附上个人编译修改的播放器:

1、实现了在Android 2.3 和Android 4.0各个平台上面的播放。

2、多格式支持

3、音视频基本同步

4、支持跳转(seek)、暂停、快进、快退、尺寸缩放等等。

5、没开启neon硬件加速时,480P的视频基本流畅播放。





转帖:/article/1415893.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: