第二十七节(gif播放)

先看一篇关于gif格式文件的原理介绍:
http://blog.csdn.net/wzy198852/article/details/17266507
播放步骤:

1.加载gif文件
2.获取到gif文件的信息,包括宽、高、帧数、每帧播放时长、当前播放到的帧的位置
3.对每帧图片进行渲染

android源码中其实提供了播放gif的类库,但是并没有提供上层调用的接口

image.png
image.png
路径:/Users/huozhenpeng/Documents/android-6.0.0_r1/external

将这些文件copy到我们的工程中

image.png

代码:

image.png

这个文件夹下的东西都是系统的,处理native-lib.cpp是我们自己写的
native-lib.cpp

#include <jni.h>
#include <string>

#include "gif_lib.h"
#include <android/bitmap.h>
#define  argb(a,r,g,b) ( ((a) & 0xff) << 24 ) | ( ((b) & 0xff) << 16 ) | ( ((g) & 0xff) << 8 ) | ((r) & 0xff)

typedef  struct GifBean
{
//正在播放的当前帧
    int currentFrame;
//记录所有帧的时长
    int *dealys;
//记录总的帧数
    int totalFrame;
} GifBean;

void  drawFrame(GifFileType *gifFileType,GifBean *gifBean,AndroidBitmapInfo info,void *pixels)
{
    //获取当前帧
    SavedImage savedImage=gifFileType->SavedImages[gifBean->currentFrame];
    GifImageDesc imageDesc=savedImage.ImageDesc;

    //某个像素位置
    int pointPixel;
    int *px= (int *) pixels;
    int *line;
    GifColorType gifColorType;
    ColorMapObject *colorMapObject=imageDesc.ColorMap;
    if(colorMapObject==NULL)
    {
       colorMapObject=gifFileType->SColorMap;
    }
    GifByteType  gifByteType;
    px = (int *)((char *)px + info.stride * imageDesc.Top);
    for(int y=imageDesc.Top;y<imageDesc.Top+imageDesc.Height;y++)
    {
        line=px;
        for(int x=imageDesc.Left;x<imageDesc.Left+imageDesc.Width;x++)
        {
            pointPixel=(y-imageDesc.Top)*imageDesc.Width+(x-imageDesc.Left);
            gifByteType=savedImage.RasterBits[pointPixel];
            //需要给每个像素赋颜色
            if(colorMapObject!=NULL)
            {

                gifColorType=colorMapObject->Colors[gifByteType];
                line[x]=argb(255,gifColorType.Red,gifColorType.Green,gifColorType.Blue);
            }

        }
        px = (int *)((char *)px + info.stride);

    }


}
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_huozhenpeng_amdemo_MainActivity_updateFrame(JNIEnv *env, jobject instance,
                                                             jobject bitmap,jlong gifPoint) {

    GifFileType * gifFileType= (GifFileType *) gifPoint;

    GifBean *gifBean= (GifBean *) gifFileType->UserData;

    AndroidBitmapInfo info;

    AndroidBitmap_getInfo(env,bitmap,&info);

    void *pixels;
    //锁定画布
    AndroidBitmap_lockPixels(env,bitmap,&pixels);
    //绘制图形
    drawFrame(gifFileType,gifBean,info,pixels);
    //控制当前播放量
    gifBean->currentFrame+=1;
    if(gifBean->currentFrame>=gifBean->totalFrame-1)
    {
        gifBean->currentFrame=0;
    }
    //解锁画布
    AndroidBitmap_unlockPixels(env,bitmap);
    return  gifBean->dealys[gifBean->currentFrame];

}



extern "C"
JNIEXPORT jint JNICALL
Java_com_example_huozhenpeng_amdemo_MainActivity_getWidth(JNIEnv *env, jobject instance,
                                                          jlong gifPoint) {
    GifFileType *gifFileType= (GifFileType *) gifPoint;

    return gifFileType->SWidth;


}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_huozhenpeng_amdemo_MainActivity_getHeight(JNIEnv *env, jobject instance,
                                                           jlong gifPoint) {

    GifFileType *gifFileType= (GifFileType *) gifPoint;

    return gifFileType->SHeight;

}

extern "C"
JNIEXPORT jlong JNICALL
Java_com_example_huozhenpeng_amdemo_MainActivity_loadGif(JNIEnv *env, jobject instance,
                                                         jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);
    int error;
    //Open a new GIF file for read, given by its name.
    GifFileType *gifFileType = DGifOpenFileName(path, &error);
    //This routine reads an entire GIF into core, hanging all its state info off the GifFileType pointer
    DGifSlurp(gifFileType);

    GifBean *gifBean= (GifBean *) malloc(sizeof(GifBean));
    memset(gifBean,0, sizeof(GifBean));

    gifBean->dealys= (int *) malloc(sizeof(int) * gifFileType->ImageCount);
    memset(gifBean->dealys,0, sizeof(int)*gifFileType->ImageCount);

    //在图形控制扩展块中的第5个字节和第6个字节存放的是每帧的延迟时间,单位是
    // 1/100秒,而唯一能标识这是一个图形扩展块的是第2个字节,固定值0xF9
    ExtensionBlock *extensionBlock;
    //给gibBean的delays赋值,它将存放所有的帧的延迟时间
    for(int i=0;i<gifFileType->ImageCount;i++)
    {
        //取出每一帧
        SavedImage frame=gifFileType->SavedImages[i];
        // Count of extensions before imag
        //遍历扩展块,取出图形扩展块的表示的时间
        for(int j=0;j<frame.ExtensionBlockCount;j++)
        {
            //#define GRAPHICS_EXT_FUNC_CODE    0xf9    /* graphics control (GIF89) */
            if(GRAPHICS_EXT_FUNC_CODE==frame.ExtensionBlocks[j].Function)
            {
               extensionBlock= &frame.ExtensionBlocks[j];
                break;
            }
        }
        if(extensionBlock)
        {
            int delay=10*((extensionBlock->Bytes[2]<<8)|extensionBlock->Bytes[1]);
            gifBean->dealys[i]=delay;
        }


    }
    gifBean->totalFrame=gifFileType->ImageCount;
    gifFileType->UserData=gifBean;
    env->ReleaseStringUTFChars(path_, path);
    return (jlong) gifFileType;
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_huozhenpeng_amdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";


    return env->NewStringUTF(hello.c_str());
}

MainActivity.java

package com.example.huozhenpeng.amdemo;

import android.Manifest;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    private ImageView iv_gif;

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv_gif= (ImageView) findViewById(R.id.iv_gif);

    }

    private int REQUEST_CAMERA_CODE=1;
    private void requestCameraAccess() {

        ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_CODE);

    }


    public void rquestPermission(View view)
    {
        requestCameraAccess();
    }

    private Bitmap bitmap;
    private int delay;
    private long gifPoint;
    public void  play(View view)
    {
        File file = new File(Environment.getExternalStorageDirectory(), "dashaguai.gif");
        gifPoint=loadGif(file.getAbsolutePath());
        int width=getWidth(gifPoint);
        int height=getHeight(gifPoint);
        bitmap=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        delay=updateFrame(bitmap,gifPoint);
        handler.sendEmptyMessageDelayed(0xa1,delay);

    }

    private Handler handler=new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            iv_gif.setImageBitmap(bitmap);
            handler.sendEmptyMessageDelayed(0xa1,delay);
            delay=updateFrame(bitmap,gifPoint);

        }
    };

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public   native  long  loadGif(String path);


    public native int getWidth(long gifPoint);
    public native int getHeight(long gifPoint);

    public native int updateFrame(Bitmap bitmap,long gifPoint);
}



CMakeList.txt


add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp
             src/main/cpp/dgif_lib.c
             src/main/cpp/egif_lib.c
             src/main/cpp/gif_err.c
             src/main/cpp/gif_hash.c
             src/main/cpp/gifalloc.c
             src/main/cpp/quantize.c
              )

find_library( # Sets the name of the path variable.
                jnigraphics-lib

                # Specifies the name of the NDK library that
                # you want CMake to locate.
                jnigraphics )



find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )



target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib}
                       ${jnigraphics-lib}
                       )

注意这块

image.png

我们播放这两个gif文件

image.png

运行结果:

image.png

遇到的问题:
在播放demo.gif的时候可以正常播放,播放dashaguai.gif的时候无法
播放,debug的时候发现在播放dashaguai.gif的时候

ColorMapObject *colorMapObject=imageDesc.ColorMap;

这个colorMapObject是为null的,有的gif确实是获取不到,这个时候我们用全局的,修改代码

ColorMapObject *colorMapObject=imageDesc.ColorMap;
    if(colorMapObject==NULL)
    {
       colorMapObject=gifFileType->SColorMap;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容