http://blog.csdn.net/chen_jie_2010/article/details/7276175
H264解码器源码,移植ffmpeg中的H264解码部分到Android,深度删减优化,在模拟器(320x480)中验证通过。
程序的采用jni架构。界面部分,文件读取,视频显示都是用java做的,底层的视频解码用C来做满足速度的要求。
在这个版本中,从H264码流中分割出Nal是在java层做的,这样在java层直接调用解码时就知道是否有显示视频,缺点的就是耦合度/封装性差一点。
如果采用在底层做Nal分割的方法,可以封装得好看一些,但是每次送的数据有限制,如果送的数据太多,底层可能会一次解码出好几帧视频,但是通知到界面层只能显示一帧,造成丢帧的现象。 如果每次送的数据较少,就会有很多次底层调用没有进行实质解码,很小气的做法,比如有一压缩数据帧需要600字节,如果一次送100个字节给解码器,那么要送6次才会进行实质解码,因为每个数据帧有大有小,所以只能取极小值才不会导致丢帧。
不过所有的编码解码都是各种因素平衡折中的结果,具体用什么方法具体分析。
如果程序崩溃退出,优先考虑:
2)byte [] NalBuf = new byte[40980]; 缓冲区是否溢出。
如果有B帧,那肯定不是baseline。
为便于支持不同分辨率的码流,修改了代码。现在只需要修改H264Android.java文件中第51,74,75行就可测试新分辨率。
有些大分辨率的码流可能会异常,优先修改H264Android.java文件中第161行把Nal缓冲区改大。
两版本都是用 android-ndk-1.6_r1-windows.zip 和 cygwin 1.7.5-1, gcc4 4.3.4-3 (用 cygcheck -c查看) 编译。
注意 /jni/H264Android.cpp文件添加了extern "C" 关键声明。
解码源码下载地址:http://files.cnblogs.com/mcodec/H264Android.7z
C++版本下载地址:http://files.cnblogs.com/mcodec/H264Android_CPP.7z
测试码流(240x320)下载地址:http://files.cnblogs.com/mcodec/butterfly.h264.rar
测试码流(352x288)下载地址:http://files.cnblogs.com/mcodec/352x288.264.7z
Feedback
1:程序里好像写死了路径,文件名。看一下是否符合。
2:程序里写死了图像的分辨率,如果是其他分辨率的可能会出问题。
3:解码库做了很大的删减,只支持baseline的。有些码流可能不符合。
建议:
用博主提供的码流文件先在模拟器上跑通,然后再修改。
不曉得是不是支援MPEG4的格式呢
如果沒有 大概要怎麼加上去呢?
還請版大指導 謝謝
如果要做mpeg4的解码库,最好还是把xvid编码部分删掉,分离出解码部分,当然你也可以一点都不删,再移植到jni。应该不是很难。
請教兩個問題:
1. 您所附的264檔案不能在VLC Player撥放, 是不是因為檔案前面帶的header?因為我想試著用您的程式去解一幀一幀的frame.
2. 關於mpeg4解碼的部分, 是不是把原本的mpegvideo.h和mpegvideo.c一起編譯進jni就可以了?
謝謝!!
2: 关于mpeg4解码部分,不仅仅是mpegvideo.c, 还要加比较多的文件。如果要用ffmpeg的mpeg4解码,建议还是从本博客的ffmpeg vc版中分离相关文件,做减法比加法要简单一些。
大概發現兩個問題
一個是delay蠻嚴重的
不曉得是software decoder解得慢
還是因為收封包和解frame放在同一個thread
這個部分修改一下應該可以改善
另一個問題是如果DecoderNal這個function回傳小於0的值
下一次運行到同一行程式就會直接終止結束(連ANR都沒有)
看debug message好像是memory位址的問題(有一些stack和heap關鍵字)
不是很確定怎麼處理
還請博主指導 謝謝
謝謝博主更新測試檔
發現用VLC撥放和在模擬器上撥放的流暢度差蠻多的 @@
我通常是在windows下把程序调试好,再移到ndk中。
装ndk,在cywin中生成的so文件。请参考ndk方面的资料。
对,我放博主的视频可以,但播放自己的一个264文件时,播了一点就直接退出了,log下面显示应该是so文件中的错误,有stack和heap关键字,请博主不吝赐教,看看到底问题出在哪儿。
目前測試解352x240的source輸出為320x240沒問題
修改了以下幾個地方即可
int iWidth=240; => int iWidth=320;
int iHeight=320; => int iHeight=240;
tmp_pic = (short*)av_malloc(320*480*2) =>
tmp_pic = (short*)av_malloc(240*640*2)
但是當source改大一點就會當掉(例如640x480)
請問博主提供的源碼該怎麼修改
才可以將影像來源為640x480(或更大)輸出為320x240的解析度?
使用ndk-build去compile博主提供的源碼就可以了
請問博主除了您提供的DisplayYUV_16這個方法之外
請問您知道怎麼使用ffmpeg提供的sws_scale嗎?
因為sws_scale也可以轉成rgb
但是我不曉得怎麼把他和android的bitmap接起來
謝謝!!
不能播放 貌似read的时候
我用的是HVGA 2.2sdk 也导入SD卡了 不过目录是/mnt/sdcard
运行程序不能播放 咋回事啊 急
不能播放 貌似read的时候
我用的是HVGA 2.2sdk 也导入SD卡了 不过目录是/mnt/sdcard
运行程序不能播放 咋回事啊 急
用1.6 的 然后加载进 /sdcard
也不能播放 咋回事捏
请问,这是什么原因,是不是h264存在多种编码格式,怎样才能支持全格式的h264文件的解码?
我附带的h264文件在1.6版下是可以播放的,在2.2下没有测试过。建议你先用1.6版把程序跑通,然后再往2.2上移。
如果你用1.6版都没有跑通,那应该是你的系统没装好,或者你的系统装了太多东西,它们之间互相打架导致1.6版都跑不动,重装系统吧。
to 恒行天下:
这个开源的h264解码器只支持baseline,关闭了很多开关,不过应该可以解码大部分的码流。如果有不能解码的,可能是码流有解码器不支持的特性。
jm代码支持全格式的h264,不过它的效率实在太低。
ffmpeg/x264是比较实用的h264解码库,不过都有删减。从实用上讲,用ffmpeg应该可以解码的。参照这个开源,你自己重新从ffmpeg中分离解码器吧。
mcodec 20101207
谢谢楼主大哥。
不过貌似ANDROID支持RTSP播放H264 也支持H264采集
不知道ANDROID 是否支持播放RTP的数据包或者解码。。。
有没有现成的API呢?
如果送进去解码的数据不对
你下个vc6版的吧,在windows下仔细跟踪调试。
to sunshine901106:
我通常是在vc6下把程序调试好,vc6下调试很方便,做些测试后再移植到其他平台。
mcodec 20101217
我的博客上有一个ffmpeg VC6版的源码包,通常是以那个源码包为基础把不需要的删掉,得到最后自己想要的codec。
to jiam:
这个具体的原因不好定论,以前碰到过一次是在mobile平台,用gapi显示就可以,用bmp位图相关函数显示就很重的马赛克,估计应该还是显示的问题。
to yangdelong:
你先用其他能很容易debug的开发环境比如vc等把你所有的代码调通,然后再移到android平台,在android平台只做简单调试,比如写文件比对来确认一下。你现在的错误不知道是那个环节有问题。
请问如果CIF解码时候
tmp_pic = (short*)av_malloc(352*576*2); // 最大320x240,16bits
这么分配对么?别的地方我都对应改成352 288了。
解码CIF时候图像大幅变化时候会崩溃。
而图像不动的时候会很正常。
我的是RTP传过来的数据有时候有丢包
这样再解码就会崩溃了
请问博主有没有好的办法解决这个问题?
请问如果CIF解码时候
tmp_pic = (short*)av_malloc(352*576*2); // 最大320x240,16bits
这么分配对么?别的地方我都对应改成352 288了。
解码CIF时候图像大幅变化时候会崩溃。
而图像不动的时候会很正常。
我的是RTP传过来的数据有时候有丢包
这样再解码就会崩溃了
请问博主有没有好的办法解决这个问题?
除了IWIDTH IHEIGHT和上面的地方 还有别的地方要改么?
为便于支持不同分辨率的码流,修改了代码。现在只需要修改H264Android.java文件中第51,74,75行就可测试新分辨率。
有些大分辨率的码流可能会异常,优先修改H264Android.java文件中第161行把Nal缓冲区改大。
能不能夠提供一個範例是在底層解碼後直接建立Bitmap給上層使用?
我的應用是接收及時影像, 但影像可能會有不同的解析度
這樣我必須建立好幾個Bitmap物件用來顯示不同解析度之影像
這種做法會導致memory leak的問題(OutOfMemoryError: bitmap size exceeds VM budget)
或是在您的範例中是否有方法動態調整並顯示不同解析度影像?
謝謝
楼主请教一个问题. 把项目的源文件c 改成 c++编译时出现异常 . 要怎么样处理 ?
Compile++ thumb: H264Android <= /cygdrive/d/android-ndk-r4/samples/jnitest/jni/c
ommon.cpp
/cygdrive/d/android-ndk-r4/samples/jnitest/jni/common.cpp: In function 'int allo
c_table(VLC*, int)':
/cygdrive/d/android-ndk-r4/samples/jnitest/jni/common.cpp:74: error:
invalid conversion from 'void*' to 'int16_t (*)[2]'
先把CHECKED_ALLOCZ宏定义展开,做强制类型转换即可。比如上面错误转换成
vlc->table = (short (*)[2])av_realloc(vlc->table, sizeof(VLC_TYPE) * 2 * vlc->table_allocated);
其他的什么const连接错误,直接把const删掉最省事。
能不能举个例子要怎么转换. 谢谢
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1896: error: invalid
conversion from 'void*' to 'int8_t (*)[8]'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1897: error: invalid
conversion from 'void*' to 'uint8_t (*)[16]'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1898: error: invalid
conversion from 'void*' to 'uint8_t*'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1899: error: invalid
conversion from 'void*' to 'uint8_t (*)[32]'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1903: error: invalid
conversion from 'void*' to 'uint8_t*'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1904: error: invalid
conversion from 'void*' to 'uint16_t*'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1905: error: invalid
conversion from 'void*' to 'int16_t (*)[2]'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1906: error: invalid
conversion from 'void*' to 'int16_t (*)[2]'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1912: error: invalid
conversion from 'void*' to 'uint16_t*'
/cygdrive/d/android-ndk-r4/samples/h264Android/jni/h264.cpp:1913: error: invalid
conversion from 'void*' to 'uint16_t*'
比如:
CHECKED_ALLOCZ(h->intra4x4_pred_mode, big_mb_num * 8 * sizeof(uint8_t));
改写成:
h->intra4x4_pred_mode =(signed char (*)[8])av_mallocz(big_mb_num * 8 * sizeof(uint8_t));
其他的类型错误也用强制类型转换解决。
cabac.h 这个文件结构体
typedef struct CABACContext
{
int low;
int range;
int outstanding_count;
uint8_t lps_range[2*64][4]; ///< rangeTabLPS
uint8_t lps_state[2*64]; ///< transIdxLPS
uint8_t mps_state[2*64]; ///< transIdxMPS
uint8_t *bytestream_start;
uint8_t *bytestream;
int bits_left; ///<
}CABACContext;
编译时出现
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:4: error:
expected initializer before 'typedef'
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:15: error: expected c
onstructor, destructor, or type conversion before ';' token
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:21: error: variable o
r field 'ff_init_cabac_decoder' declared void
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:21: error: 'CABACCont
ext' was not declared in this scope
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:21: error: expected p
rimary-expression before '*' token
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:21: error: 'buf' was
not declared in this scope
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:21: error: expected p
rimary-expression before 'int'
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:22: error: variable o
r field 'ff_init_cabac_states' declared void
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:22: error: 'CABACCont
ext' was not declared in this scope
/cygdrive/d/android-ndk-r4/samples/H264Android/jni/cabac.h:22: error: expected p
rimary-expression before 'const'
需要怎么解决
你下c++的版本吧。
刚刚接触ffmpeg,想播放多种格式的,不清楚要分离哪些?请问学习ffmpeg应该从哪里入手?谢谢...
博主非常热心. 非常感谢 .
在CreateBitmap那邊就有錯誤訊息:
4147200-byte external allocation too large for this process.
有解決辦法嗎?謝謝..
在本博客有本ffmpeg/ffplay源码注释的电子书,和可以在vc6下编译运行的移植版本,先把电子书看得差不多明白应该就知道咋做了。
to caxton:
目前android手机还没有达到1920x1080的分辨率,依具体手机型号的分辨率创建同样大小的bitmap,在jni层做缩放就可以了。
你好. 请问有. 在jni层下载创建 Bitmap 并显示的例子吗 ? 能否提供一份示例代码
对跳帧的问题,请各位网友 首先定位是网络丢包还是手机跑不动还是postInvalidate()函数导致的,如果确认是postInvalidate()函数导致的,目前我没有太好的办法,如果是其他原因,再针对性修改。我们以前做网络的时候帧率很低,丢不丢帧,图像都是跳跳的,所以没有特别处理这个问题。
我也测试了下,用我们公司的设备端的352x288码流(就一个i帧),测试结果如下:就显示了部分图像,然后过了将近6-8秒,NDK库就挂了,用博主提供的测试文件,用2.2的模拟器看的非常的流畅
现在有一个问题就是,如果需要支持high级别的解码,该进行些什么样的修改?ffmpeg本身应该是支持high级别的解码吧?
恩,已解决,用的方法基本上和博主说的一样。我原来有个VC6的能解high级别的代码,改改就能在android上用了。
谢谢了。/
你先把流媒体服务器接受下数据包分离出裸数据保存成文件,然后也可以用其他播放器测试,保证h264裸数据没问题。
如果裸数据没问题还是播会儿就崩,那可能要换解码器,参照此代码,重新从ffmpeg中分离解码库。
博主,你好,首先谢谢你的建议。我将流媒体服务器传过来的264 rtp分离出裸数据并保存为文件播放,由于采用的是UDP传输避免不了会有丢包的可能,所以放出来的部分画面有马赛克的现象。可以确保h264裸数据没有问题,看来就得换解码器了。
Feedback
--------------------------
04-15 07:42:21.310 I/DEBUG ( 88): #00 pc 0000cbb4 /system/lib/libc.so
04-15 07:42:21.310 I/DEBUG ( 88): #01 pc 00004c9c /data/data/com.test/lib/libh264android.so (put_pixels8_c)
04-15 07:42:21.310 I/DEBUG ( 88): #02 pc 00004ccc /data/data/com.test/lib/libh264android.so (put_pixels16_c)
04-15 07:42:21.310 I/DEBUG ( 88): #03 pc 00004ce8 /data/data/com.test/lib/libh264android.so
04-15 07:42:21.310 I/DEBUG ( 88): #04 pc 000091c6 /data/data/com.test/lib/libh264android.so
04-15 07:42:21.310 I/DEBUG ( 88): #05 pc 000092f6 /data/data/com.test/lib/libh264android.so
04-15 07:42:21.310 I/DEBUG ( 88): #06 pc 0000aa64 /data/data/com.test/lib/libh264android.so
04-15 07:42:21.310 I/DEBUG ( 88): #07 pc 0000e9ac /data/data/com.test/lib/libh264android.so
04-15 07:42:21.310 I/DEBUG ( 88): #08 pc 000111d0 /data/data/com.test/lib/libh264android.so (decode_frame)
04-15 07:42:21.310 I/DEBUG ( 88): #09 pc 00001506 /data/data/com.test/lib/libh264android.so (Java_com_test_CameraViewSelf_DecoderNal)
352x288文件改一下后缀名,把后缀名改为.h264即可。看来vlc是判断文件后缀名来识别文件的,不太可靠的方法。
@路人Z
看来多半是解码库出了错,可能是那地方越界了,也可能是码流不符合baseline等标准,你重新从本网站的ffmpeg中分离一个解码库吧。
@sunshine901106
本代码中很清楚了,用函数Java_h264_com_VView_DecoderNal(JNIEnv* env, jobject thiz, jbyteArray in, jint nalLen, jbyteArray out)中的out参数回传给java代码,再用 canvas.drawBitmap(VideoBit, 0, 0, null); 显示出来
你先把模拟器设置成320x480,然后在java代码中跟踪一下VView::run()函数,看一下有没有进到while循环,定位程序在哪里异常退出。
估计是文件没有拷贝到sd卡中。
vv.PlayVideo(file)是菜单选择消息响应函数,不至于选一个菜单项,不到响应函数那里去吧。做菜单是最基础的东西,你找同事帮忙看一下代码。
这个错误是为什么呢?
如果你要在自己的工程中使用,必须保证packet/class名字一致。
我也是,图像码流大时,如:大幅晃动时,或帧率速度快时,崩溃,可能溢出。楼主可以测试一下
mPixel byte数组是返回解码后的rgb565数据,可以用bitmap的方法显示到手机屏上。
rgb565格式每个像素为16bit,所以是2=16bit/8bit,换算成字节。如果是用rgb24格式显示就是3=24bit/8bit,但有些手机不支持rgb24,几乎所有手机都支持rgb565.
int mTrans=0x0F0F0F0F;
Temp =SockBuf[i+SockBufUsed];
mTrans <<= 8;
mTrans |= Temp;
if(mTrans == 1) // 找到一个开始字
...
temp是buffer中的值,为啥和mTrans 或呢?很是困惑呢
mTrans参数的作用是查找开始字,做nal分割。H264里面的开始字是00 00 00 01,首先给mTrans赋初值0x0f0f0f0f(这个值尽量不要和00 00 00 01像即可,也可以用其他的值),把mTrans左移8位后,做或运算是在低位拼接上从缓冲区中取出的一个字节,然后判断是否是开始字。
不用指针加偏移量,取整数再和0x1比较的方法,是因为X86是小端CPU,00 00 00 01表示的是字节序列,在内存中如果用指针去取值,结果是0x1000000(大小端不匹配)。
“为便于支持不同分辨率的码流,修改了代码。现在只需要修改H264Android.java文件中第51,74,75行就可测试新分辨率。”
博主前头已经提了
目前是用bitmap显示视频的,你可以用bitmap的序列函数做缩放来调整最终显示在屏上的画面大小,也可以在jni层自己做缩放来调整大小。
解码播放速度不是本参考代码的考虑范围。
@leomok:
参考码流是用x264编码出来的,尽量不要打开控制开关。
视频显示:SurfaceView<Skia>
在java端用SurfaceView显示视频。通过SurfaceView.getHolder() 取得surface holder ,而SurfaceHolder.lockCanvas() 得到SkCanvas 。将这个SkCanvas通过JNI传入NDK Code中,便可以在NDK中对这个SkCanvas作画啦,之后用SurfaceHolder.unlockCanvasAndPost() ,將內容更新到画面上。注意,SurfaceHolder.lockCanvas() 得到的SkCanvas 并不会保存的內容。参考代码:
A frameworks/base/core/java/android/view/Surface.java
B frameworks/base/core/jni/android_view_Surface.cpp
C frameworks/base/libs/ui/SurfaceComposerClient.cpp
D frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp
ps:Android有一个Graphic Engine ,称为Skia,Skia主要的class type 是SkCanvas。
录像直接用Android Camera.
你搜一下 ffmpeg android ndk 等关键字。
https://github.com/lhzhang/FFMpeg(测试时模拟器设置为320x480)
https://github.com/tewilove/faplayer等代码.
我看过一些在jni层直接实现视频输出的代码,有些能跑,有些不能跑。
你搜一下 ffmpeg android ndk 等关键字。
https://github.com/lhzhang/FFMpeg(测试时模拟器设置为320x480)
https://github.com/tewilove/faplayer等代码.
非常感谢. 我试试
QQ:51298322
应该是我移植FFMPEG出现的问题,在UBUNTU下我编译FFMPEG,利用自带的FFPLAY播放是没有问题的,问题就是出在移植到android上
https://github.com/lhzhang/FFMpeg(测试时模拟器设置为320x480)
https://github.com/tewilove/faplayer等代码.
博主你好.下载这两个项目都运行不起来.
lhzhang/FFMpeg 这个项目编译通不过
按照lhzhang/FFMpeg 将 jni\include\android\surface.h audiotrack.h 头文件复制到自己的项目中.
编译的时候一直提示引用了无效的videoDriver_register_t VideoDriver_register = AndroidSurface_register; 等函数
麻烦博主有时间. 写个在JNI 层通过surface 绘制的DEMO .非常感激!
@黄瓜炒鸡蛋,程序显示的思想是如果原始视频图像分辨率比手机屏分辨率大,就上下左右丢边,显示中间的图像,如果比手机屏分辨率小,就居中显示,程序没有做缩放。没仔细看width,height变量的影响。
非常感激. 前进的道路有你. !
因为此开源代码是从网络播放器中删减而来,所以是sockbuf。
NalBufUsed和SockBufUsed是计数控制变量。
int mTrans=0x0F0F0F0F 为监视是否是0x00000001开始字而定义的变量,其初值尽量和0x00000001开始字不相关,可以是其他值。
或者你看一下h264的标准可能会更好的理解。
如果是你自己的测试媒体文件,那可能是其他异常,可能是nalbuf小了,或者非baseline规格,这需要仔细调试。
profile:level : Baseline:1.3 解码失败
请问一下.博主这是什么总是 ? 要怎么解决?
已经发了. 请查收. 谢谢
谢谢. 我向公司反映一下情况
使用您的代码得到的一帧数据,可以draw到surfaceView上,实现播放.
我现在想把它保存成jpg图片存到sdcard上.
问题就是rgb的怎么转jpg的.
如果一定要保存成jpg文件,你用其他的库转换bmp文件到jpg也比较简单。
如果你不想写bmp文件,那你就去找jpg压缩库吧,android应该自带,但不知道接口好不好用,特别要注意rgb565,yuv等等格式的差别。
你也可以在本网站下载vc6的版本,在windows下自己跟踪调试。
我把播放文件流改爲接受udp流做實時播放
可以實時播放了 但播了大約10秒左右 程序自動退出了
不知道是什麽原因...
期待您的答復 謝謝
剛剛看了網友也有相關的問題
您提到了檢查裸流,我查了 沒問題
然後要換解碼器? 不是很明白 要怎樣換?換哪個?
另外 我想問網絡那邊扔過來的大小 和nalbuf 的大小 是不是和這個問題有聯係?
還有讀取2048byte 似乎也不能改..
期待你的回答 謝謝
检查裸码流看是否符合baseline要求,这个主要看编码器那边打开了那些开关。
nalbuf和图像大小,带宽有关。现在是一次解码一个完整的nal单元,如果图像大,带宽大,导致nal单元大,那nalbuf也要大些,和网络包大小没什么关系。
2048是一个临时的缓冲区,大小可以改。
对应于你这种情况,我会把接受的网络码流保存成本地文件,然后用开源的播放器播,看哪个播放器能正确的播放,然后从开源代码中分离和优化解码器,换掉不能播放的解码器。
很感激博主的回答
我重新用了最新的ffmpeg源碼 參考你的JNI文件 重新提取了
現在10秒自動退出的問題沒有了
但是晃動劇烈時 就會卡住 並隔一會自動退出
之前有網友問了 請問現在有沒有這個問題的解決方案?
謝謝
注意,可以多用几个原始的ffmpeg版本测试。
可能的检查方向,sps/pps等信息是否正确,码流数据包是否完整,编码器是否打开了解码器不支持的开关。
拍照功能简单,bmp有rgb565格式的,只要把bmp文件头写对即可,可以在java中实现,也可以在jni层实现。
录像功能也简单,因为是在java层做的nal分割,保存好sps,pps,需要录像时,把sps和pps先写到文件,然后识别IDR帧开始录像。不过开发这部分代码需要懂一些H264标准。
快播慢播只需要修改时钟,此demo代码没有做时钟控制,最简单就是sleep函数了。
seek功能就复杂多了,要计算总时间和换算相当偏移,还要查找idr帧。
博主你好 不知爲何 發你的郵箱 tslking@tom.com 發不出..
我發了站内信給你 有空幫我看看 謝謝
@cruisehuang:
拍照功能简单,bmp有rgb565格式的,只要把bmp文件头写对即可,可以在java中实现,也可以在jni层实现。
录像功能也简单,因为是在java层做的nal分割,保存好sps,pps,需要录像时,把sps和pps先写到文件,然后识别IDR帧开始录像。不过开发这部分代码需要懂一些H264标准。
快播慢播只需要修改时钟,此demo代码没有做时钟控制,最简单就是sleep函数了。
seek功能就复杂多了,要计算总时间和换算相当偏移,还要查找idr帧。
能否提供一份DEMO代码至cruisehuang@126.com,刚刚接触H264,很多概念比较生疏,谢谢!
如果JM代码正常,ffmpeg代码不正常,要不找其他开源的能正确跑的解码器,从其他的地方移植。或者debug JM的代码,看码流到底打开了什么鬼鬼开关,自己在ffmpeg代码中添加上对这个开关的支持,当然这个难度很大。
博主,为什么我用jm播放不了我的视频文件,而用vlc却能很流畅的播放我的h264文件呢?用快播也能很流畅的播放
public native int InitDecoder(int width, int height);
public native int UninitDecoder();
public native int DecoderNal(byte[] in, int insize, byte[] out);
第一个InitDecoder在main.c.old中没有找到,InitDecoder函数的定义在哪啊?
后面两个也是,我也木有在main.c.old找到函数定义如何在main.c.old选择哪几个函数作为java中的C接口函数呢?
Android版run()函数是根据main.c.old写出来的吗?写这个函数是怎么根据main.c.old写出来的的思路是什么呢?
还有这个while (!Thread.currentThread().isInterrupted())是不是对照main.c.old中的while(!feof(inpf))写出来的?
使用javah生成的H264Android.h头文件怎么没有呢?
H264Android.c中也没有包含使用javah生成的H264Android.h头文件
main.c.old是在vc6下调试使用的文件,因为在android版不用这个文件就加了一个.old的后缀。
使用javah生成的h264android.h文件直接改后缀名成了h264android.c文件,因为没有复杂的函数调用关系可以不用包含此.h文件。
因为android分java和jni两层,和vc6下的单层有些不同,Initdecoer()等接口函数基本重新改写。
可以简单认为读到的数据字节数小于0就到了文件末尾,while(!feof(inpf))相对应的应该是下列代码段
if(bytesRead<=0)
break;
(1)也就是说这个h264android.c文件不是编写的是根据javah生成的h264android.h文件直接写,.h文件放的内容只有声明没有定义,怎么可以直接该( ⊙ o ⊙ )啊!?
是不是应该由javah生成的h264android.h之后,我们再根据这个生成的.h文件把main.c.old中所有的string,int之类的格式全部改成jstring,jint之类的,就写成了相应的.c?
(2)这三个入口函数的原型在main.c.old里面木有找到哇,博主是怎么想到的呢?我们导师让我把opensvc的给移植过去,我怎么从main.c函数中选择哪些函数作为入口函数呢?博主大大 这几个入口函数选择有什么原则吗?如何在main.c.old选择哪几个函数作为java中的C接口函数呢?
(3) while (!Thread.currentThread().isInterrupted())这段函数能否不在java层实现呢?否则在java层实现的话 要把大量的C代码改写成JAVA?
(1) 是不是从main.c函数中选择几个java的C函数入口 用java生成.h文件 然后把main.c全部按照这个.h的定义格式修改下呢?
(2)博主的h264android.c的代码在jint Java_h264_com_VView_InitDecoder之前的CreateYUVTab_16()和DisplayYUV_16()中的数据格式int是不是要改成jint?jint Java_h264_com_VView_DecoderNal()中的int也不用改写格式?
(3)main.c.old中的if(iBytesPixel==2) 和两个else if是不是对应java层的NAL解析呢?博主把这个在底层做Nal分割的代码写到java中的改动好大啊 这里改动幅度看起来表示很吃力的说
main.c.old中的if(iBytesPixel==2) 和两个else if对应的是RGB565,RGB24,RGB32这三个颜色空间,不同的平台支持的颜色空间可能不同。
while (!Thread.currentThread().isInterrupted())这个判断语句只是java的线程相关函数,在其他平台上可以简单的判断按键来决定是否退出线程。
在jni层,jint和int貌似通用,改不改依个人习惯,不过貌似改成jint比较符合jni的一些规范。
一般简单的库基本上就是三个接口函数,一个初始化函数,一个功能函数,一个反初始化函数,各函数的参数根据需要添加。在此项目中,这三个接口函数先在H264Android.java文件中定义好,然后用javah生成.h接口文件,然后参考main.c.old文件写个.c文件实现.h文件声明的函数,.c文件实现后,发现.h文件貌似多余,就把.h文件删除了。
Nal分割放在java层做,java层调用jni层,这个是通过三个native接口函数调用,但是要是把Nal分割放在jni底层做的话,能看出来java层调用jni层,可是木有看到jni层要调用java层,这个是怎么回事,通过哪些个函数调用?
善良的博主大大 我对这个.h接口文件还是有些疑惑,能否把你用javah生成的.h接口文件给我发一份呢\(^o^)/~?在H264Android.java文件中定义这三个接口函数之后,是不是不用立即就可以用javah生成的.h接口文件,之后再在H264Android.java中添加编写while (!Thread.currentThread().isInterrupted()) 及MergeBuffer()拷贝到nalbuf缓冲区开始字做nal分割的这段代码?还是吧这个H264Android.java全部补齐后,再用用javah生成的.h接口文件?
当然,你也可以在jni层直接输出视频,本blog有相关示例,这样jni层就不用调用java层了。
现在一直没有调用javah生成.h文件了,都是直接拼接出jni函数名,你可以看一下网上jni方面的文章,一大把。
记忆中定义好接口函数后,编译一下,再调用javah生成.h文件,不用补齐.java文件。
如果要系统自动调用,就要编译系统,烧录rom之类的工作,普通的应用程序不应该烧录rom。
如果自己写一个播放器,然后自己调用编解码库,工作量不可小视。
此demo完全脱离android自带的libstagefright和opencore架构,除了音视频输出的效率不是特高外,基本上是最简单最容易的实现方案。
请问博主能否在推荐个开源的代码 让咱能感受下 接口函数的选取 及在.java中的native声明和在.c中的实现的代码,以我现在的知识对照着博主这个改写opensvc还是很有困难的
还有就是不但木有找到接口函数nativePlay()的实现代码,怎么又把不是接口函数的两个函数jniRegisterNativeMethods()和 FFMpegPlayerAndroid_play()也按照jni的格式写了?
我看在H264Android.c中只是对接口函数按照jni的格式给实现了,并没有实现DeleteYUVTab(), DisplayYUV_16之类的非接口函数代码?
对比着看FFMpegPlayerAndroid.cpp和H264Android.c,我对jni接口函数的选取和参考main.c.old文件写个.c文件实现.h文件声明的函数更加疑惑
h264android.c中的视频输出是在java层用bmp序列函数实现的,所以要有DeleteYUVTab()等yuv到rgb565转换的相关函数。
ffplay中的视音频输出是调用libffplay.so库中的函数直接在jni层输出,yuv到rgb的转换在libswscale子目录下的函数中已经实现了,不用再做转换所以看不到DeleteYUVTab()等函数。
貌似android直接支持rtsp协议,但好像不好用,ffmpeg是直接支持rtmp和rtsp协议的,但需要重新移植。
如果仅仅只支持rtsp协议,移植live555也可以。
02-13 11:53:55.057: ERROR/InputDispatcher(131): channel '408967c8 h264.com/h264.com.H264Android (server)' ~ Channel is unrecoverably broken and will be disposed!
我自己的H264文件,测试出现这个问题,请问楼主怎么解决?????