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

来源:互联网 发布:求最小公倍数算法 编辑:程序博客网 时间:2024/04/29 02:20

/********************************************************************************************
 * author:conowen@大钟                                                                                                                          
 * E-mail:conowen@hotmail.com                                                                                                             
 * http://blog.csdn.net/conowen                                                                                                              
 * 注:本文为原创,仅作为学习交流使用,转载请标明作者及出处。      

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



之前的这篇博文http://blog.csdn.net/conowen/article/details/7526398

所提及到的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

/* * 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 8using 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::ConfigconvertPixelFormat(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 voidinitBitmap(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(视频输出接口部分)

//-------------------- 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)

08-16 21:46:41.863: E/FFMpegMediaPlayer(2263): waiting on video thread08-16 21:46:41.873: I/FFMpegVideoDecoder(2263): videoclock---->  6.68000008-16 21:46:41.883: E/SurfaceTextureClient(2263): Surface::lock failed, already locked08-16 21:46:41.893: I/FFMpegVideoDecoder(2263): videoclock---->  6.72000008-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的视频基本流畅播放。





原创粉丝点击