急求ffmpeg h264 解码解码部分移植到 DSP上的可用代码

H264解码器在DSP上的实现
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
H264解码器在DSP上的实现
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
[精品]H_264解码在ADDSP_BF533上的实现和优化
下载积分:420
内容提示:[精品]H_264解码在ADDSP_BF533上的实现和优化
文档格式:PDF|
浏览次数:0|
上传日期: 05:25:03|
文档星级:
该用户还上传了这些文档
[精品]H_264解码在ADDSP_BF533上的实现和优化.PDF
官方公共微信基于H264编解码DSP的实现硕士论文是硕士研究生所撰写的学术论文,具有一定的理论..
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
基于H264编解码DSP的实现
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口1.移植目标
将H.264解码器移植到OPhone操作系统之上(NDK+C),并写一个测试程序(OPhoneSDK+Java)测试解码库是否正常运行,下面是解码时的截图:
OPhone的模拟器和Mobile的模拟器一样是模拟ARM指令的,不像Symbian模拟器一样执行的是本地代码,所以在模拟器上模拟出来的效率会比真实手机上的效率要低,之前这款解码器已经优化到在nokia 6600(相当低端的一款手机,CPU主频才120Hz)上做到在线播放。
2.面向人群
本文面向有一定的手机应用开发经验(例如:S60/Mobile/MTK)和有一定的跨手机平台移植经验的人员,帮助她们了解一个企业的核心库(C/C++)是怎么移植到OPhone之上的。
3.假定前提
1)熟悉Java/C/C++语言;
2)熟悉Java的JNI技术;
3)有一定的跨手机平台移植经验;
4)有一套可供移植的源代码库,这里以H.264解码库为例,为了保护我们的知识版权,这里只能够公开头文件:
#ifndef __H264DECODE_H__
#define __H264DECODE_H__
#if defined(__SYMBIAN32__)  //S602rd/3rd/UIQ
     #include 
     #include 
     #include 
     #include 
#else                       //Windows/Mobile/MTK/OPhone
     #include 
     #include 
     #include 
class H264Decode
     /***************************************************************************/
     /* 构造解码器                                                        */
     /* @return H264Decode解码器实例                                      */
     /***************************************************************************/
     static H264Decode *H264DecodeConstruct();
     /***************************************************************************/
     /* 解码一帧                                                     */
     /* @pInBuffer   指向H264的视频流                                      */
     /* @iInSize H264视频流的大小                                      */
     /* @pOutBuffer  解码后的视频视频                                        */
     /* @iOutSize    解码后的视频大小                                        */
     /* @return      已解码的H264视频流的尺寸                              */
     /***************************************************************************/
     int DecodeOneFrame(unsigned char *pInBuffer,unsigned int iInSize,unsigned char *pOutBuffer,unsigned int &iOutSize);
     ~H264Decode();
#endif  // __H264DECODE_H__
你不用熟悉OPhone平台,一切从零开始,因为在此之前,我也不熟悉。
4.开发环境(请参考: /documentation/)
5.移植过程
5.1 移植流程
5.2 封装Java接口
在&假定前提&中提到了要移植的函数,接下来会编写这些 函数的Java Native Interface。
package ophone.streaming.video.h264;
import java.nio.ByteB
public class H264decode {
//H264解码库指针,因为Java没有指针一说,所以这里用一个32位的数来存放指针的值
     private long H264decode = 0;
     static{
         System.loadLibrary("H264Decode");
     }
     public H264decode() {
         this.H264decode = Initialize();
     }
     public void Cleanup() {
         Destroy(H264decode);
     }
     public int DecodeOneFrame(ByteBuffer pInBuffer,ByteBuffer pOutBuffer) {
         return DecodeOneFrame(H264decode, pInBuffer, pOutBuffer);
     }
     private native static int DecodeOneFrame(long H264decode,ByteBuffer pInBuffer,ByteBuffer pOutBuffer);
     private native static long Initialize();
     private native static void Destroy(long H264decode);
这块没什么好说的,就是按照H264解码库的函数,封装的一层接口,如果你熟悉Java JNI,会发现原来是这么类似。这里插入一句:我一直认为技术都是相通的,底层的技术就那么几种,学懂了,其它技术都是一通百通。
5.3 使用C实现本地方法
5.3.1生成头文件
使用javah命令生成JNI头文件,这里需要注意是class路径不是源代码的路径,并且要加上包名:
这里生成了一个ophone_streaming_video_h264_H264decode.h,我们打开来看看:
#include 
#ifndef _Included_ophone_streaming_video_h264_H264decode
#define _Included_ophone_streaming_video_h264_H264decode
#ifdef __cplusplus
extern "C" {
JNIEXPORT jint JNICALL Java_ophone_streaming_video_h264_H264decode_DecodeOneFrame
   (JNIEnv *, jclass, jlong, jobject, jobject);
JNIEXPORT jlong JNICALL Java_ophone_streaming_video_h264_H264decode_Initialize
   (JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_ophone_streaming_video_h264_H264decode_Destroy
   (JNIEnv *, jclass, jlong);
#ifdef __cplusplus
5.3.2 实现本地方法
之前已经生成了JNI头文件,接下来只需要实现这个头文件的几个导出函数,这里以H264解码器的实现为例:
#include "ophone_streaming_video_h264_H264decode.h"
#include "H264Decode.h"
JNIEXPORT jint JNICALL Java_ophone_streaming_video_h264_H264decode_DecodeOneFrame
   (JNIEnv * env, jclass obj, jlong decode, jobject pInBuffer, jobject pOutBuffer) {
     H264Decode *pDecode = (H264Decode *)
     unsigned char *In = NULL;unsigned char *Out = NULL;
     unsigned int InPosition = 0;unsigned int InRemaining = 0;unsigned int InSize = 0;
     unsigned int utSize = 0;
     jint DecodeSize = -1;
     jbyte *InJbyte = 0;
     jbyte *OutJbyte = 0;
     jbyteArray InByteArrary = 0;
     jbyteArray utByteArrary = 0;
     //获取Input/Out ByteBuffer相关属性
     {
         //Input
         {
             jclass ByteBufferClass = env->GetObjectClass(pInBuffer);
             jmethodID PositionMethodId = env->GetMethodID(ByteBufferClass,"position","()I");
             jmethodID RemainingMethodId = env->GetMethodID(ByteBufferClass,"remaining","()I");
             jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");
             InPosition = env->CallIntMethod(pInBuffer,PositionMethodId);
             InRemaining = env->CallIntMethod(pInBuffer,RemainingMethodId);
             InSize = InPosition + InR
             InByteArrary = (jbyteArray)env->CallObjectMethod(pInBuffer,ArraryMethodId);
             InJbyte = env->GetByteArrayElements(InByteArrary,0);
             In = (unsigned char*)InJbyte + InP
         }
         //Output
         {
             jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);
             jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");
             jmethodID ClearMethodId = env->GetMethodID(ByteBufferClass,"clear","()Ljava/nio/B");
             //清理输出缓存区  
             env->CallObjectMethod(pOutBuffer,ClearMethodId);
             utByteArrary = (jbyteArray)env->CallObjectMethod(pOutBuffer,ArraryMethodId);
             utJbyte = env->GetByteArrayElements(OutByteArrary,0);
             ut = (unsigned char*)OutJ
         }
     }
     //解码
     DecodeSize = pDecode->DecodeOneFrame(In,InRemaining,Out,OutSize);
     //设置Input/Output ByteBuffer相关属性
     {
         //Input
         {
             jclass ByteBufferClass = env->GetObjectClass(pInBuffer);
             jmethodID SetPositionMethodId = env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/B");
             //设置输入缓冲区偏移  
             env->CallObjectMethod(pInBuffer,SetPositionMethodId,InPosition + DecodeSize);
         }
         //Output
         {
             jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);
             jmethodID SetPositionMethodId = env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/B");
             //设置输出缓冲区偏移  
             env->CallObjectMethod(pOutBuffer,SetPositionMethodId,OutSize);
         }
     }
     //清理  
     env->ReleaseByteArrayElements(InByteArrary,InJbyte,0);
     env->ReleaseByteArrayElements(OutByteArrary,OutJbyte,0);
     return DecodeS
JNIEXPORT jlong JNICALL Java_ophone_streaming_video_h264_H264decode_Initialize
   (JNIEnv * env, jclass obj) {
     H264Decode *pDecode = H264Decode::H264DecodeConstruct();
     return (jlong)pD
JNIEXPORT void JNICALL Java_ophone_streaming_video_h264_H264decode_Destroy
   (JNIEnv * env, jclass obj, jlong decode) {
     H264Decode *pDecode = (H264Decode *)
     if (pDecode)
     {
         delete pD
         pDecode = NULL;
     }
5.3.3 编译本地方法
接下来,只需要把用C实现的本地方法编译为动态链接库,如果之前你用于移植的那个库曾经移植到Symbian上过,那么编译会相当简单,因为NDK的编译器和Symbian的编译器一样,都是采用GCC做交叉编译器。
首先,需要在$NDK"apps目录下,创建一个项目目录,这里创建了一个H264Decode目录,在H264Decode目录中,创建一个Android.mk文件:
APP_PROJECT_PATH := $(call my-dir)
APP_MODULES   := H264Decode 
接下来,需要在$NDK"source目录下,创建源代码目录(这里的目录名要和上面创建的项目目录文件名相同),这里创建一个H264Decode目录,然后把之前生成的JNI头文件和你实现的本地方法相关头文件和源代码,都拷贝到   这个目录下面。
然后,我们编辑Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE  := H264Decode
LOCAL_SRC_FILES := common.c cabac.c utils.c golomb.c mpegvideo.c mem.c imgconvert.c h264decode.cpp h264.c dsputil.c ophone_streaming_video_h264_H264decode.cpp
include $(BUILD_SHARED_LIBRARY)
关于Android.mk文件中,各个字段的解释,可以参考$NDK"doc下的《OPHONE-MK.TXT》和《OVERVIEW.TXT》,里面有详细的介绍。
最后,我们启动Cygwin,开始编译:
如果你看到了Install:**,这说明你的库已经编译好了。
如果编译遇到下面错误,怎么办?
error: redefinition of typedef 'int8_t'
需要注释掉你的代码中&typedef signed char  int8_t;&,如果你的代码之前是已经移植到了Mobile/Symbian上的话,很有可能遇到这个问题。
5.4 编写库测试程序
用Eclipse创建一个OPhone工程,在入口类中输入如下代码:
 * @author ophone
 * @email 
package ophone.streaming.video.h264;
import java.io.F
import java.io.FileInputS
import java.io.InputS
import java.nio.ByteB
import OPhone.app.A
import OPhone.graphics.BitmapF
import OPhone.os.B
import OPhone.os.H
import OPhone.os.M
import OPhone.widget.ImageV
import OPhone.widget.TextV
public class H264Example extends Activity {
    private static final int VideoWidth = 352;
    private static final int VideoHeight = 288;
    private ImageView ImageLayout = 
    private TextView FPSLayout = 
    private H264decode Decode = 
    private Handler H = 
    private byte[] Buffer = 
    private int DecodeCount = 0;
    private long StartTime = 0;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ImageLayout = (ImageView) findViewById(R.id.ImageView);
        FPSLayout = (TextView) findViewById(R.id.TextView);
        Decode = new H264decode();
        StartTime = System.currentTimeMillis();
        new Thread(new Runnable(){
            public void run() {
                StartDecode();
            }
        }).start();
        H = new Handler(){
            public void handleMessage(Message msg) {
                ImageLayout.invalidate();
                ImageLayout.setImageBitmap(BitmapFactory.decodeByteArray(Buffer, 0, Buffer.length));
                long Time = (System.currentTimeMillis()-StartTime)/1000;
                if(Time > 0){
                    FPSLayout.setText("花费时间:" + Time + "秒  解码帧数:" + DecodeCount + "  FPS:" + (DecodeCount/Time) );
                }
            }
        };
    private void StartDecode(){
        File h264file = new File("/tmp/Demo.264");
        InputStream h264stream = 
        try {
            h264stream = new FileInputStream(h264file);
            ByteBuffer pInBuffer = ByteBuffer.allocate(51200);//分配50k的缓存  
            ByteBuffer pRGBBuffer = ByteBuffer.allocate(VideoWidth*VideoHeight*3);
            while (h264stream.read(pInBuffer.array(), pInBuffer.position(), pInBuffer.remaining()) >= 0) {
                pInBuffer.position(0);
                do{
                    int DecodeLength = Decode.DecodeOneFrame(pInBuffer, pRGBBuffer);
                    //如果解码成功,把解码出来的图片显示出来
                    if(DecodeLength > 0 && pRGBBuffer.position() > 0){
                        //转换RGB字节为BMP
                        BMPImage bmp = new BMPImage(pRGBBuffer.array(),VideoWidth,VideoHeight);
                        Buffer = bmp.getByte();
                        H.sendMessage(H.obtainMessage());
                        Thread.sleep(1);
                        DecodeCount ++;
                    }
                }while(pInBuffer.remaining() > 10240);//确保缓存区里面的数据始终大于10k
                //清理已解码缓冲区
                int Remaining = pInBuffer.remaining();
                System.arraycopy(pInBuffer.array(), pInBuffer.position(), pInBuffer.array(), 0, Remaining);
                pInBuffer.position(Remaining);
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        } finally {
            try{h264stream.close();} catch(Exception e){}
        }
    protected void onDestroy() {
        super.onDestroy();
        Decode.Cleanup();
BMPImage是一个工具类,主要用于把RGB序列,转换为BMP图象用于显示:
@author ophone
  * @email 
package ophone.streaming.video.h264;
import java.nio.ByteB
public class BMPImage {
     // --- 私有常量
     private final static int BITMAPFILEHEADER_SIZE = 14;
     private final static int BITMAPINFOHEADER_SIZE = 40;
     // --- 位图文件标头
     private byte bfType[] = { 'B', 'M' };
     private int bfSize = 0;
     private int bfReserved1 = 0;
     private int bfReserved2 = 0;
     private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;
     // --- 位图信息标头
     private int biSize = BITMAPINFOHEADER_SIZE;
     private int biWidth = 176;
     private int biHeight = 144;
     private int biPlanes = 1;
     private int biBitCount = 24;
     private int biCompression = 0;
     private int biSizeImage = biWidth*biHeight*3;
     private int biXPelsPerMeter = 0x0;
     private int biYPelsPerMeter = 0x0;
     private int biClrUsed = 0;
     private int biClrImportant = 0;
     ByteBuffer bmpBuffer = 
     public BMPImage(byte[] Data,int Width,int Height){
         biWidth = W
         biHeight = H
         biSizeImage = biWidth*biHeight*3;
         bfSize = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + biWidth*biHeight*3;
         bmpBuffer = ByteBuffer.allocate(BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + biWidth*biHeight*3);
         writeBitmapFileHeader();
         writeBitmapInfoHeader();
         bmpBuffer.put(Data);
     }
     public byte[] getByte(){
         return bmpBuffer.array();
     }
     private byte[] intToWord(int parValue) {
         byte retValue[] = new byte[2];
         retValue[0] = (byte) (parValue & 0x00FF);
         retValue[1] = (byte) ((parValue >> 8) & 0x00FF);
         return (retValue);
     }
     private byte[] intToDWord(int parValue) {
         byte retValue[] = new byte[4];
         retValue[0] = (byte) (parValue & 0x00FF);
         retValue[1] = (byte) ((parValue >> 8) & 0x000000FF);
         retValue[2] = (byte) ((parValue >> 16) & 0x000000FF);
         retValue[3] = (byte) ((parValue >> 24) & 0x000000FF);
         return (retValue);
     }
     private void writeBitmapFileHeader () {
         bmpBuffer.put(bfType);
         bmpBuffer.put(intToDWord (bfSize));
         bmpBuffer.put(intToWord (bfReserved1));
         bmpBuffer.put(intToWord (bfReserved2));
         bmpBuffer.put(intToDWord (bfOffBits));
     }
     private void writeBitmapInfoHeader () {
         bmpBuffer.put(intToDWord (biSize));
         bmpBuffer.put(intToDWord (biWidth));
         bmpBuffer.put(intToDWord (biHeight));
         bmpBuffer.put(intToWord (biPlanes));
         bmpBuffer.put(intToWord (biBitCount));
         bmpBuffer.put(intToDWord (biCompression));
         bmpBuffer.put(intToDWord (biSizeImage));
         bmpBuffer.put(intToDWord (biXPelsPerMeter));
         bmpBuffer.put(intToDWord (biYPelsPerMeter));
         bmpBuffer.put(intToDWord (biClrUsed));
         bmpBuffer.put(intToDWord (biClrImportant));
     }
测试程序完整工程在此暂不提供。
5.5 集成测试
集成测试有两点需要注意,在运行程序前,需要把动态库复制到模拟器的/system/lib目录下面,还需要把需要解码的视频传到模拟器的/tmp目录下。
这里要明确的是,OPhone和Symbian的模拟器都做的太不人性化了,Symbian复制一个文件到模拟器中,要进一堆很深的目录,OPhone的更恼火,需要敲命令把文件传递到模拟器里,说实话,仅在这点上,Mobile的模拟器做的还是非常人性化的。
PATH=D:"OPhone"OPhone SDK"tools"
adb.exe remount
adb.exe push D:"Eclipse"workspace"H264Example"libs"armeabi"libH264Decode.so /system/lib
adb.exe push D:"Eclipse"workspace"H264Example"Demo.264 /tmp
这里解释一下abd push命令:
    - 复制文件或者目录到模拟器
在Eclipse中,启动库测试程序,得到画面如下:
模拟器黑屏怎么办?
这可能是由于模拟器启动速度比较慢所引起的,所以需要多等一会。希望下个版本能够改进。
声明:该文章系网友上传分享,此内容仅代表网友个人经验或观点,不代表本网站立场和观点;若未进行原创声明,则表明该文章系转载自互联网;若该文章内容涉嫌侵权,请及时向上学吧网站投诉>>
上一篇:下一篇:
相关经验教程
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益

我要回帖

更多关于 h264解码 的文章

 

随机推荐