在Android平台上实现H264解码,一般采用开源的ffmpeg来实现,那么这就涉及一个问题:如何在android平台上移植ffmpeg?
这个移植的方法在网上有一大推,本人看得头晕,所以采用了一个取巧的办法:在android平台上编译XBMC的时候,编译成功后,在目录~/xbmc-android/tools/android/packaging/xbmc/lib/armeabi-v7a/ 下面就有编译好的ffmpeg的库,直接提取出来用就可以了
注:关于如何在android平台上编译XBMC,请看我之前的博文:
那么有了android平台上ffmpeg的库,如何在android平台上测试H264解码呢?
新建android app工程ffmpeg_android
gedit ./.bashrc
将 /opt/android-sdk-linux/tools 添加到 "PATH"环境变量中
android list targets
android create project --target 1 --name ffmpeg_android --path ~/workspace/ffmpeg_android --package com.modukaikai.ffmpeg --activity ffmpegActivity
将xbmc中的ffmpeg源码拷贝到工程ffmpeg_android的jni目录下
mkdir ~/workspace/ffmpeg_android/jni
cp -R ~/xbmc-android/lib/ffmpeg ~/workspace/ffmpeg_android/jni/
H264解码器的实现
vim ~/workspace/ffmpeg_android/jni/h264_decoder.h
以下是h264_decoder.h的代码:
#ifndef h264_decoder_h
#define h264_decoder_h
extern "C"
{
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavcodec/avcodec.h"
typedef void (*tp_avcodec_register_all)(void);
typedef AVCodec *(*tp_avcodec_find_decoder)(enum AVCodecID id);
typedef AVCodecContext *(*tp_avcodec_alloc_context3)(const AVCodec *codec);
typedef int (*tp_avcodec_open2)(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
typedef AVFrame *(*tp_avcodec_alloc_frame)(void);
typedef void (*tp_avcodec_free_frame)(AVFrame **frame);
typedef int (*tp_avcodec_decode_video2)(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt);
typedef int (*tp_avcodec_close)(AVCodecContext *avctx);
typedef void (*tp_av_free)(void *ptr);
typedef void (*tp_av_init_packet)(AVPacket *pkt);
class H264DecoderInterface
{
public:
H264DecoderInterface()
{
p_avcodec_register_all = NULL;
p_avcodec_find_decoder = NULL;
p_avcodec_alloc_context3 = NULL;
p_avcodec_open2 = NULL;
p_avcodec_alloc_frame = NULL;
p_avcodec_free_frame = NULL;
p_avcodec_decode_video2 = NULL;
p_avcodec_close = NULL;
p_av_free = NULL;
p_av_init_packet = NULL;
};
~H264DecoderInterface()
{
};
void (*p_avcodec_register_all)(void);
AVCodec *(*p_avcodec_find_decoder)(enum AVCodecID id);
AVCodecContext *(*p_avcodec_alloc_context3)(const AVCodec *codec);
int (*p_avcodec_open2)(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
AVFrame *(*p_avcodec_alloc_frame)(void);
void (*p_avcodec_free_frame)(AVFrame **frame);
int (*p_avcodec_decode_video2)(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt);
int (*p_avcodec_close)(AVCodecContext *avctx);
void (*p_av_free)(void *ptr);
void (*p_av_init_packet)(AVPacket *pkt);
};
class h264_decoder
{
public:
static bool loadLibrary(const char *libDir);
static bool unloadLibrary();
h264_decoder();
~h264_decoder();
bool open_h264_decoder();
unsigned long h264_decoder_process(unsigned char* pSrcData, unsigned long srcDataLen, unsigned char* pDstData, bool& bNoOutputDecData);
bool close_h264_decoder();
void setFrameRate(int frameRate);
void setResolution(int width, int height);
private:
static void* avcodec_handle;
static void* avfilter_handle;
static void* avformat_handle;
static void* avutil_handle;
static void* postproc_handle;
static void* swresample_handle;
static void* swscale_handle;
static H264DecoderInterface *p_H264DecoderInterface;
struct AVCodec *p_AVCodec;
struct AVCodecContext *p_AVCodecContext;
struct AVFrame *p_AVFrame;
struct AVPacket avPacket;
int got_frame;
bool isOpened;
int video_frameRate;
int video_width;
int video_height;
};
}
#endif