H264解码器源码,移植ffmpeg中的H264解码部分到Android,深度删减优化,在模拟器(320x480)中验证通过。
程序的采用jni架构。界面部分,文件读取,视频显示都是用java做的,底层的视频解码用C来做满足速度的要求。
在这个版本中,从H264码流中分割出Nal是在java层做的,这样在java层直接调用解码时就知道是否有显示视频,缺点的就是耦合度/封装性差一点。
如果采用在底层做Nal分割的方法,可以封装得好看一些,但是每次送的数据有限制,如果送的数据太多,底层可能会一次解码出好几帧视频,但是通知到界面层只能显示一帧,造成丢帧的现象。 如果每次送的数据较少,就会有很多次底层调用没有进行实质解码,很小气的做法,比如有一压缩数据帧需要600字节,如果一次送100个字节给解码器,那么要送6次才会进行实质解码,因为每个数据帧有大有小,所以只能取极小值才不会导致丢帧。
不过所有的编码解码都是各种因素平衡折中的结果,具体用什么方法具体分析。
如果程序崩溃退出,优先考虑:
1)是否是baseline
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楼 回复 引用 查看
by atwyr
正在使用博主的源码进行试验,发现在机器上跑320X240的码流刷帧不流畅,不知博主有没有什么好的方法完善这个问题,坐等博主牛人的解答。
#2楼 222.90.193.* 回复 引用
by dirking[未注册用户]
为什么跑出来时黑屏呢
#3楼 回复 引用 查看
by icoo
我把测试文件导入sdcard,安装应用后,也是黑屏,请问是为啥呢?我用的是2.1的包和2.1的模拟器
#4楼 116.231.101.* 回复 引用
by 本博客博主[未注册用户]
可能的原因:
1:程序里好像写死了路径,文件名。看一下是否符合。
2:程序里写死了图像的分辨率,如果是其他分辨率的可能会出问题。
3:解码库做了很大的删减,只支持baseline的。有些码流可能不符合。
建议:
用博主提供的码流文件先在模拟器上跑通,然后再修改。
#5楼 回复 引用 查看
by ckvir
請問這代碼可以用在串流上嗎??
就是接一張一張的frame
邊接邊解碼??
#6楼 60.251.61.* 回复 引用
by caxton[未注册用户]
jni裡面有mpegvideo.h
不曉得是不是支援MPEG4的格式呢
如果沒有 大概要怎麼加上去呢?
還請版大指導 謝謝
#7楼 116.231.116.* 回复 引用
by 本博客博主[未注册用户]
mpegvideo.h 已经删掉很多很多东西了,只留下最小的代码来解码h264.
如果要做mpeg4的解码库,最好还是把xvid编码部分删掉,分离出解码部分,当然你也可以一点都不删,再移植到jni。应该不是很难。
#8楼 60.251.61.* 回复 引用
by caxton[未注册用户]
謝謝博主回覆
請教兩個問題:
1. 您所附的264檔案不能在VLC Player撥放, 是不是因為檔案前面帶的header?因為我想試著用您的程式去解一幀一幀的frame.
2. 關於mpeg4解碼的部分, 是不是把原本的mpegvideo.h和mpegvideo.c一起編譯進jni就可以了?
謝謝!!
#9楼 116.231.119.* 回复 引用
by 本博客博主[未注册用户]
1: 264测试文件已经更新,可以在vlc中播放了。vlc 测试版本的编译者是 jb on sasmira.jbkempf.com(Jun 21 2010 02:34:50)
2: 关于mpeg4解码部分,不仅仅是mpegvideo.c, 还要加比较多的文件。如果要用ffmpeg的mpeg4解码,建议还是从本博客的ffmpeg vc版中分离相关文件,做减法比加法要简单一些。
#10楼 60.251.61.* 回复 引用
by caxton[未注册用户]
運用在視訊串流上是ok的(解一幀一幀的frame)
大概發現兩個問題
一個是delay蠻嚴重的
不曉得是software decoder解得慢
還是因為收封包和解frame放在同一個thread
這個部分修改一下應該可以改善
另一個問題是如果DecoderNal這個function回傳小於0的值
下一次運行到同一行程式就會直接終止結束(連ANR都沒有)
看debug message好像是memory位址的問題(有一些stack和heap關鍵字)
不是很確定怎麼處理
還請博主指導 謝謝
#11楼 60.251.61.* 回复 引用
by caxton[未注册用户]
@本博客博主
謝謝博主更新測試檔
發現用VLC撥放和在模擬器上撥放的流暢度差蠻多的 @@
#12楼 222.90.193.* 回复 引用
by dir4678[未注册用户]
问下,现在android下怎么调式和跟踪c程序里,编译通过,有时候会出现运行期间的错误,这种情况下已经打成的so文件怎么取调试。谢谢。
#13楼 117.88.80.* 回复 引用
by bingle[未注册用户]
请问,如何才能由c文件生成so文件,用GCC吗?就用jni文件夹中的Android.mk?
#14楼 116.231.127.* 回复 引用
by 本博客博主[未注册用户]
旧版的ndk好像不可以调试和跟踪c代码,新版的好像可以,请参阅其他ndk的资料。
我通常是在windows下把程序调试好,再移到ndk中。
装ndk,在cywin中生成的so文件。请参考ndk方面的资料。
#15楼 121.229.54.* 回复 引用
by bingle[未注册用户]
引用 caxton:
運用在視訊串流上是ok的(解一幀一幀的frame)
大概發現兩個問題
一個是delay蠻嚴重的
不曉得是software decoder解得慢
還是因為收封包和解frame放在同一個thread
這個部分修改一下應該可以改善
另一個問題是如果DecoderNal這個function回傳小於0的值
下一次運行到同一行程式就會直接終止結束(連ANR都沒有)
看debug message好像是memory位址的問題(有一些stack和heap關鍵字)
不是很確定怎麼處理
還請博主指導 謝謝
对,我放博主的视频可以,但播放自己的一个264文件时,播了一点就直接退出了,log下面显示应该是so文件中的错误,有stack和heap关键字,请博主不吝赐教,看看到底问题出在哪儿。
#16楼 60.251.61.* 回复 引用
by caxton[未注册用户]
請問博主和各位先進:
目前測試解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的解析度?
#17楼 60.251.61.* 回复 引用
by caxton[未注册用户]
@bingle
使用ndk-build去compile博主提供的源碼就可以了
#18楼 60.251.61.* 回复 引用
by caxton[未注册用户]
剛剛的發文忘了一個問題
請問博主除了您提供的DisplayYUV_16這個方法之外
請問您知道怎麼使用ffmpeg提供的sws_scale嗎?
因為sws_scale也可以轉成rgb
但是我不曉得怎麼把他和android的bitmap接起來
謝謝!!
#19楼 122.89.3.* 回复 引用
by memset[未注册用户]
butterfly.264是YV12编码,请问,YV12编码和H264编码不是一个概念吧?
#20楼 回复 引用 查看
by echozhang
抛出异常了啊
不能播放 貌似read的时候
我用的是HVGA 2.2sdk 也导入SD卡了 不过目录是/mnt/sdcard
运行程序不能播放 咋回事啊 急
#21楼 回复 引用 查看
by echozhang
抛出异常了啊
不能播放 貌似read的时候
我用的是HVGA 2.2sdk 也导入SD卡了 不过目录是/mnt/sdcard
运行程序不能播放 咋回事啊 急
用1.6 的 然后加载进 /sdcard
也不能播放 咋回事捏
#22楼 回复 引用 查看
by 恒行天下
有的h264的文件可以播放,但是还有一部分h264文件不能播放。
请问,这是什么原因,是不是h264存在多种编码格式,怎样才能支持全格式的h264文件的解码?
#23楼[楼主] 回复 引用 查看
by mcodec
to echozhang:
我附带的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
#24楼 回复 引用 查看
by echozhang
我可以解码了 CIF也可以了
谢谢楼主大哥。
不过貌似ANDROID支持RTSP播放H264 也支持H264采集
不知道ANDROID 是否支持播放RTP的数据包或者解码。。。
有没有现成的API呢?
#25楼 119.117.141.* 回复 引用
by echo.zhang[未注册用户]
楼主 DECODENAL会造成输入越界么
如果送进去解码的数据不对
#26楼 回复 引用 查看
by sunshine901106
你好,,,请问如何在windows下把程序调试好,再移到ndk中,,,谢谢
#27楼 116.226.234.* 回复 引用
by 本博客博主[未注册用户]
to echo.zhang:
你下个vc6版的吧,在windows下仔细跟踪调试。
to sunshine901106:
我通常是在vc6下把程序调试好,vc6下调试很方便,做些测试后再移植到其他平台。
mcodec 20101217
#28楼 回复 引用 查看
by yang.guofu
很不错的东西,程序可以运行,就是在播放有些H264文件程序会崩溃。提示的错误是:segmentation fault
#29楼 202.113.3.* 回复 引用
by yangdelong[未注册用户]
博主大大,为什么我导入会黑屏呢?我想在android上播放rtsp的H.264视频,视频会交由其他人进行取帧处理,所以想自己对视频进行解码,请您多帮助,我qq251667151,感激不尽!
#30楼 113.79.192.* 回复 引用
by jiam[未注册用户]
下了你Symbian和Android的两个版本试都可以用,但是就是遇到一个问题是解我的一个baseline的bitstream会有拖尾和马赛克现象,个人估计多半是运动处理部分的问题,有运动物体时多半跟不上造成拖尾,但解码慢点就好很多。不知是否还有其它原因??敬请赐教。
#31楼 回复 引用 查看
by sunshine901106
你好!你是如何分离出ffmpeg的libavcodec,!还是直接把整个libavcodec库直接拿到Cygwin编译,请指教!谢谢!
#32楼 116.231.111.* 回复 引用
by 本博客博主[未注册用户]
to sunshine901106:
我的博客上有一个ffmpeg VC6版的源码包,通常是以那个源码包为基础把不需要的删掉,得到最后自己想要的codec。
to jiam:
这个具体的原因不好定论,以前碰到过一次是在mobile平台,用gapi显示就可以,用bmp位图相关函数显示就很重的马赛克,估计应该还是显示的问题。
to yangdelong:
你先用其他能很容易debug的开发环境比如vc等把你所有的代码调通,然后再移到android平台,在android平台只做简单调试,比如写文件比对来确认一下。你现在的错误不知道是那个环节有问题。
#33楼 回复 引用 查看
by echozhang
博主你好
请问如果CIF解码时候
tmp_pic = (short*)av_malloc(352*576*2); // 最大320x240,16bits
这么分配对么?别的地方我都对应改成352 288了。
解码CIF时候图像大幅变化时候会崩溃。
而图像不动的时候会很正常。
我的是RTP传过来的数据有时候有丢包
这样再解码就会崩溃了
请问博主有没有好的办法解决这个问题?
#34楼 回复 引用 查看
by echozhang
博主你好
请问如果CIF解码时候
tmp_pic = (short*)av_malloc(352*576*2); // 最大320x240,16bits
这么分配对么?别的地方我都对应改成352 288了。
解码CIF时候图像大幅变化时候会崩溃。
而图像不动的时候会很正常。
我的是RTP传过来的数据有时候有丢包
这样再解码就会崩溃了
请问博主有没有好的办法解决这个问题?
除了IWIDTH IHEIGHT和上面的地方 还有别的地方要改么?
#35楼 116.231.127.* 回复 引用
by 本博客博主[未注册用户]
重新上传了压缩包,主要的修改是支持多分辨率。
为便于支持不同分辨率的码流,修改了代码。现在只需要修改H264Android.java文件中第51,74,75行就可测试新分辨率。
有些大分辨率的码流可能会异常,优先修改H264Android.java文件中第161行把Nal缓冲区改大。
#36楼 回复 引用 查看
by 布儿
博主,只能播放.264或h264格式的吗? mp4格式不行吗
#37楼 116.231.105.* 回复 引用
by 本博客博主[未注册用户]
此版本只能播.264或.h264格式,mp4格式不行。
#38楼 60.251.61.* 回复 引用
by caxton[未注册用户]
請問博主:
能不能夠提供一個範例是在底層解碼後直接建立Bitmap給上層使用?
我的應用是接收及時影像, 但影像可能會有不同的解析度
這樣我必須建立好幾個Bitmap物件用來顯示不同解析度之影像
這種做法會導致memory leak的問題(OutOfMemoryError: bitmap size exceeds VM budget)
或是在您的範例中是否有方法動態調整並顯示不同解析度影像?
謝謝
#39楼 121.33.160.* 回复 引用
by free2010[未注册用户]
博主你好. 请教一个问题. 在NDK 接收H.264网络视频数据. 解码后 .有没有好的办法. 通知到界面更新解码的帧
#40楼 116.226.232.* 回复 引用
by 本博客博主[未注册用户]
在ndk里面可以通知到界面更新,你找一下网上的文章,jni支持java层调用ndk里面的函数,同时也支持ndk函数调用java层函数。如果你这样做,ndk里面就要开一个线程,又要麻烦一些。
#41楼 218.19.61.* 回复 引用
by free2010[未注册用户]
试了通过jni 调用 postInvalidate 方法 . 出现跳帧的情况
#42楼 121.32.171.* 回复 引用
by free2010[未注册用户]
楼主请教一个问题. 把项目的源文件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]'
#43楼 121.32.171.* 回复 引用
by free2010[未注册用户]
楼主你好. 把解码库转换成c++ 出现很多数据类型需要转换. 有没有好的解决 方法 ?
#44楼 116.231.116.* 回复 引用
by 本博客博主[未注册用户]
没什么好办法,只能是土办法。
先把CHECKED_ALLOCZ宏定义展开,做强制类型转换即可。比如上面错误转换成
vlc->table = (short (*)[2])av_realloc(vlc->table, sizeof(VLC_TYPE) * 2 * vlc->table_allocated);
其他的什么const连接错误,直接把const删掉最省事。
#45楼 218.19.63.* 回复 引用
by free2010[未注册用户]
楼主有时间帮我们弄个c++ 版本的吧. 菜鸟级的改这些文件难度太大了
#46楼 218.19.63.* 回复 引用
by free2010[未注册用户]
博主你好. CHECKED_ALLOCZ 这个函数发生很多类型转换错误
能不能举个例子要怎么转换. 谢谢
/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*'
#47楼 116.231.96.* 回复 引用
by 本博客博主[未注册用户]
把CHECKED_ALLOCZ改掉,提示什么类型错误就强制转换成什么类型。
比如:
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));
其他的类型错误也用强制类型转换解决。
#48楼 218.19.63.* 回复 引用
by free2010[未注册用户]
博主你好
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'
需要怎么解决
#49楼 116.231.118.* 回复 引用
by 本博客博主[未注册用户]
现在同时提供c和c++版本,c++版本在我这里编译没有你所说的错误。
你下c++的版本吧。
#50楼 回复 引用 查看
by sunshine901106
博主你好!
刚刚接触ffmpeg,想播放多种格式的,不清楚要分离哪些?请问学习ffmpeg应该从哪里入手?谢谢...
#51楼 113.111.70.* 回复 引用
by free2010[未注册用户]
引用 本博客博主:
现在同时提供c和c++版本,c++版本在我这里编译没有你所说的错误。
你下c++的版本吧。
博主非常热心. 非常感谢 .
#52楼 60.251.61.* 回复 引用
by caxton[未注册用户]
請問博主解過HD高清畫質(1920x1080)嗎?
在CreateBitmap那邊就有錯誤訊息:
4147200-byte external allocation too large for this process.
有解決辦法嗎?謝謝..
#53楼 116.231.118.* 回复 引用
by 本博客博主[未注册用户]
to sunshine901106:
在本博客有本ffmpeg/ffplay源码注释的电子书,和可以在vc6下编译运行的移植版本,先把电子书看得差不多明白应该就知道咋做了。
to caxton:
目前android手机还没有达到1920x1080的分辨率,依具体手机型号的分辨率创建同样大小的bitmap,在jni层做缩放就可以了。
#54楼 218.19.112.* 回复 引用
by bluestorm[未注册用户]
引用 caxton:
請問博主解過HD高清畫質(1920x1080)嗎?
在CreateBitmap那邊就有錯誤訊息:
4147200-byte external allocation too large for this process.
有解決辦法嗎?謝謝..
你好. 请问有. 在jni层下载创建 Bitmap 并显示的例子吗 ? 能否提供一份示例代码
#55楼 121.33.161.* 回复 引用
by bluestorm[未注册用户]
博主你好 .在jni 接收网络h.264 码流. 解码成功后. 通过jbyteArray 传回到java层. 并在jni 层调用Java View 的 postInvalidate方法更新界面. 目前出现跳帧的情况. 麻烦楼主指点博主
#56楼 116.226.225.* 回复 引用
by 本博客博主[未注册用户]
对大图像的处理,在java层创建屏分辨率大小的bitmap,在jni层解码后用c语言做缩小计算,再把缩小图像的数据传给java层显示。不是在jni层创建bitmap,也没有相应的范例。由于是缩小计算,最简单的方法,最邻近算法 抽点就可以,不需要双线性插值算法。
对跳帧的问题,请各位网友 首先定位是网络丢包还是手机跑不动还是postInvalidate()函数导致的,如果确认是postInvalidate()函数导致的,目前我没有太好的办法,如果是其他原因,再针对性修改。我们以前做网络的时候帧率很低,丢不丢帧,图像都是跳跳的,所以没有特别处理这个问题。
#57楼 219.139.144.* 回复 引用
by 韩国美女[未注册用户]
@dirking
我也测试了下,用我们公司的设备端的352x288码流(就一个i帧),测试结果如下:就显示了部分图像,然后过了将近6-8秒,NDK库就挂了,用博主提供的测试文件,用2.2的模拟器看的非常的流畅
#58楼 115.195.133.* 回复 引用
by 不愿孤独[未注册用户]
博主真是活雷锋啊,帮了大忙了
现在有一个问题就是,如果需要支持high级别的解码,该进行些什么样的修改?ffmpeg本身应该是支持high级别的解码吧?
#59楼 116.231.125.* 回复 引用
by 本博客博主[未注册用户]
如果要支持high级别的解码,你以这个版本为指导,从ffmpeg中重新把相关文件拷贝出来,低版本的一个文件可能对应高版本的几个文件,再把编译错误改掉,就差不多了,接口基本不用动。
#60楼 115.195.131.* 回复 引用
by 不愿孤独[未注册用户]
@本博客博主
恩,已解决,用的方法基本上和博主说的一样。我原来有个VC6的能解high级别的代码,改改就能在android上用了。
谢谢了。/
#61楼 61.135.195.* 回复 引用
by lvton[未注册用户]
目前正在看代码,有问题再请教博主,先膜拜下
#62楼 218.241.236.* 回复 引用
by limitfan[未注册用户]
非常感谢!
#63楼 122.233.199.* 回复 引用
by moonpuppy[未注册用户]
请问博主,用这个源码解出来的数据是yuv420格式的吗?我转换成RGB24显示,全屏都是红色的。y数据是picture->data[0],u是picture->data[1],picture->data[2],是这样么?
#64楼 116.231.97.* 回复 引用
by 本博客博主[未注册用户]
解码出来是yuv420格式,用DisplayYUV_16()函数转换成rgb16显示,c版的h264android.c文件中的Java_h264_com_VView_DecoderNal()函数中有写yuv文件的部分代码可参考。
#65楼 回复 引用 查看
by moonpuppy
博主真是好人阿,我用DisplayYUV_16()转换成rgb16可以显示的。就是转换成rgb24的显示不了。估计是取的yuv数据没取对。
#66楼 回复 引用 查看
by manshow
虽然只能用博主给的码流,自己录的码流就不行了
包括博主的VC版本,解几帧就崩掉了
但还是很感谢博主
#67楼 116.231.97.* 回复 引用
by 本博客博主[未注册用户]
to manshow,以这个jni源码为参考,重新从ffmpeg中分离能解你录的码流的源码,接口之类不用改,并且不网站有windows下可编译的最新版ffmpeg下载,生手两三周内应该可以搞定。
#68楼 210.15.122.* 回复 引用
by EminemT[未注册用户]
博主,我使用你的代码接收流媒体服务器传过来的h264 rtp,可以显示图像,但过了一会程序就崩溃了,Logcat里面就是一些stack和heap關鍵字,请问博主该如何解决这个问题?
#69楼 116.231.121.* 回复 引用
by 本博客博主[未注册用户]
to eminemt,分两步走。
你先把流媒体服务器接受下数据包分离出裸数据保存成文件,然后也可以用其他播放器测试,保证h264裸数据没问题。
如果裸数据没问题还是播会儿就崩,那可能要换解码器,参照此代码,重新从ffmpeg中分离解码库。
#70楼 210.15.122.* 回复 引用
by EminemT[未注册用户]
@本博客博主
博主,你好,首先谢谢你的建议。我将流媒体服务器传过来的264 rtp分离出裸数据并保存为文件播放,由于采用的是UDP传输避免不了会有丢包的可能,所以放出来的部分画面有马赛克的现象。可以确保h264裸数据没有问题,看来就得换解码器了。
#71楼 回复 引用 查看
by maolingbo
请问博主:我用的是1.6的模拟器,屏幕大小默认,但是始终显示一个黑框,没有视频显示。下载了您给的测试码流(352x288)和解码源码。DEBUG程序时候程序总是不知跑哪去。。。
#72楼 回复 引用 查看
by sunshine901106
博主你好!ffmpeg解码后保存成yuv格式的可以播放,请问如何传给android上的bitmap显示?
Feedback
#73楼 122.146.44.* 回复 引用
by 路人Z[未注册用户]
博主你好!如果影片解析一段時後就會發生錯誤,彈出code dump如下,想請問博主要如果解此問題,謝謝~
--------------------------
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)
#74楼 119.109.106.* 回复 引用
by zy91550[未注册用户]
352X288文件在vlc中播放不了?什么原因
#75楼 116.231.98.* 回复 引用
by 本博客博主[未注册用户]
@zy91550
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); 显示出来
#76楼 回复 引用 查看
by maolingbo
请问博主:我用的是1.6的模拟器,屏幕大小默认,但是始终显示一个黑框,没有视频显示。下载了您给的测试码流(352x288)和解码源码。DEBUG程序时候程序总是不知跑哪去。。。
#77楼 116.231.106.* 回复 引用
by 本博客博主[未注册用户]
@ maolingbo
你先把模拟器设置成320x480,然后在java代码中跟踪一下VView::run()函数,看一下有没有进到while循环,定位程序在哪里异常退出。
估计是文件没有拷贝到sd卡中。
#78楼 回复 引用 查看
by maolingbo
博主:跟踪了,连vv.PlayVideo(file)都没有运行到。SD卡上放文件了
#79楼 116.231.124.* 回复 引用
by 本博客博主[未注册用户]
@maolingbo
vv.PlayVideo(file)是菜单选择消息响应函数,不至于选一个菜单项,不到响应函数那里去吧。做菜单是最基础的东西,你找同事帮忙看一下代码。
#80楼 回复 引用 查看
by maolingbo
没有调通。。不过还是感谢博主,也没同事帮忙,自己再研究研究。。。赞博主人品。。。
#81楼 125.39.110.* 回复 引用
by lvton[未注册用户]
引用 bingle:
引用caxton:
運用在視訊串流上是ok的(解一幀一幀的frame)
大概發現兩個問題
一個是delay蠻嚴重的
不曉得是software decoder解得慢
還是因為收封包和解frame放在同一個thread
這個部分修改一下應該可以改善
另一個問題是如果DecoderNal這個function回傳小於0的值
下一次運行到同一行程式就會直接終止結束(連ANR都沒有)
看debug message好像是memory位址的問題(有一些stack和heap關鍵字)
不是很確定怎麼處理
還請博主指導 謝謝
对,我放博主的视频可以,但播放自己的一个264...
这个错误是为什么呢?
#82楼 125.39.110.* 回复 引用
by lvton[未注册用户]
我一直出现这个错误,要怎么改,望博主赐教
#83楼 116.231.113.* 回复 引用
by 本博客博主[未注册用户]
jni生成的so库,函数名带有packet名字,class名字,如果这些不一致就不能使用。
如果你要在自己的工程中使用,必须保证packet/class名字一致。
#84楼 119.109.106.* 回复 引用
by zy91550[未注册用户]
@本博客博主
我也是,图像码流大时,如:大幅晃动时,或帧率速度快时,崩溃,可能溢出。楼主可以测试一下
#85楼 回复 引用 查看
by 布儿
@本博客博主
嘿嘿,是的,今天做实验也得出这个结论~~谢谢博主
#86楼 回复 引用 查看
by tmy13
博主您好,我想把您在android实现的代码移植到java上。但是我碰到了点问题,我想知道您每次调用 iTemp = DecoderNal(NalBuf, NalBufUsed - 4, mPixel); 后返回出来的 mPixel byte数组是个什么值?我应该怎么处理?为什么开头的定义是 byte[] mPixel = new byte[width * height * 2];而不是 *3?
#87楼 116.231.113.* 回复 引用
by 本博客博主[未注册用户]
@tmy13
mPixel byte数组是返回解码后的rgb565数据,可以用bitmap的方法显示到手机屏上。
rgb565格式每个像素为16bit,所以是2=16bit/8bit,换算成字节。如果是用rgb24格式显示就是3=24bit/8bit,但有些手机不支持rgb24,几乎所有手机都支持rgb565.
#88楼 113.65.225.* 回复 引用
by 我要努力学习[未注册用户]
博主你好!请问如何控制播放速度? 我现在遇到的问题是播放快了1倍。
#89楼 123.177.17.* 回复 引用
by 曼妮莎[未注册用户]
博主,我想试着把这个程序放到android2.1的源码里编译,因为我刚刚接触所以弱弱的问一下博主,这个C的程序应该放到android2.1的里的那个文件夹里编译呢?
#90楼 123.177.17.* 回复 引用
by 曼妮莎[未注册用户]
博主你好,刚才的问题恕我愚昧,我已经知道了,我现在有个问题想请教博主,通常一个解码库怎样能挂载到framework上呢,都需要大概的几个步骤呢?我现在想把opencore的解码库挂在android的framework上,遇到了些困难,因为看您已经成功将ffmpeg中的H264解码部分移植到Android上了,想问问通常移植这么一个解码库的几个大体的步骤应该是什么呢~?我刚刚开始学android的中间以下层,所以问的问题比较愚昧,还请您包含。
#91楼 回复 引用 查看
by 布儿
博主您好,mTrans这个参数的使用不太明白。
int mTrans=0x0F0F0F0F;
Temp =SockBuf[i+SockBufUsed];
mTrans <<= 8;
mTrans |= Temp;
if(mTrans == 1) // 找到一个开始字
...
temp是buffer中的值,为啥和mTrans 或呢?很是困惑呢
#92楼 116.231.105.* 回复 引用
by 本博客博主[未注册用户]
@ 布儿:
mTrans参数的作用是查找开始字,做nal分割。H264里面的开始字是00 00 00 01,首先给mTrans赋初值0x0f0f0f0f(这个值尽量不要和00 00 00 01像即可,也可以用其他的值),把mTrans左移8位后,做或运算是在低位拼接上从缓冲区中取出的一个字节,然后判断是否是开始字。
不用指针加偏移量,取整数再和0x1比较的方法,是因为X86是小端CPU,00 00 00 01表示的是字节序列,在内存中如果用指针去取值,结果是0x1000000(大小端不匹配)。
#93楼 221.12.171.* 回复 引用
by Dez[未注册用户]
请问下博主,如果要播放QCIF 176*144的话,应该在代码的哪里进行修改?
#94楼 回复 引用 查看
by 布儿
@Dez
“为便于支持不同分辨率的码流,修改了代码。现在只需要修改H264Android.java文件中第51,74,75行就可测试新分辨率。”
博主前头已经提了
#95楼 221.12.171.* 回复 引用
by gfd123[未注册用户]
请问一下,怎么样才能做到 全屏显示视频?
#96楼 回复 引用 查看
by 山间笔客
善良的博主,求助了,呵呵,请问下,我现在所接收的视频是qcif 176x144和cif 352x288,请问下怎么调整显示画面的大小呢,另外是感觉你上传的那个裸数据在andrdoid2.2上播放起来怎么有点缓慢?是本来就如此还是怎么滴?我在android的文档里看到public void drawBitmap (int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint) 这个方法好像可以更加快速的更新图片
#97楼 221.4.221.* 回复 引用
by leomok[未注册用户]
请问博主,要怎样编码的文件才能播放?
#98楼 116.231.127.* 回复 引用
by 本博客博主[未注册用户]
@山间笔客:
目前是用bitmap显示视频的,你可以用bitmap的序列函数做缩放来调整最终显示在屏上的画面大小,也可以在jni层自己做缩放来调整大小。
解码播放速度不是本参考代码的考虑范围。
@leomok:
参考码流是用x264编码出来的,尽量不要打开控制开关。
#99楼 回复 引用 查看
by tmy13
@本博客博主
谢谢博主的回答,一下子豁然开朗了
#100楼 回复 引用 查看
by 布儿
博主,如果想要考虑解码播放的速度,与实际的相符,应该从从何处着手呢?不要解完一帧就马上显示,得考虑实际的帧率。jni呢还是外面的java代码处?希望博主点播一二。感激不尽!
#101楼 218.19.114.* 回复 引用
by free2010[未注册用户]
博主你好. 在jni 层怎么实现绘制解码后的视频 ?在jni 层直接绘制会不会效率更高. 我找到一段介绍的. 不是很明白. 博主有时间能否实现给我们看看 ? 谢谢先.
视频显示:SurfaceView
在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.
#102楼 116.231.101.* 回复 引用
by 本博客博主[未注册用户]
我看过一些在jni层直接实现视频输出的代码,有些能跑,有些不能跑。
你搜一下 ffmpeg android ndk 等关键字。
https://github.com/lhzhang/FFMpeg(测试时模拟器设置为320x480)
https://github.com/tewilove/faplayer等代码.
#103楼 121.33.74.* 回复 引用
by free2010[未注册用户]
引用 本博客博主:
我看过一些在jni层直接实现视频输出的代码,有些能跑,有些不能跑。
你搜一下 ffmpeg android ndk 等关键字。
https://github.com/lhzhang/FFMpeg(测试时模拟器设置为320x480)
https://github.com/tewilove/faplayer等代码.
非常感谢. 我试试
#104楼 回复 引用 查看
by Mical Steve
博主,你用弄编码,压缩吗?先在这里谢谢博主的h264解码源码
#105楼 回复 引用 查看
by manshow
你好,最近移植了整个FFMPEG到android上,拿几个H264文件测试,结果在测试i.MX27编码器编的H.264文件的时候能解,但好像是解的不对,所以想博主方便的话,帮我测试一下看
QQ:51298322
#106楼 116.231.99.* 回复 引用
by 本博客博主[未注册用户]
@manshow,我一直都是用x264编码出来的码流做测试源,并且都是在vc6下把源码调试通之后才移到android的,不在android下调试。
#107楼 回复 引用 查看
by manshow
@本博客博主
应该是我移植FFMPEG出现的问题,在UBUNTU下我编译FFMPEG,利用自带的FFPLAY播放是没有问题的,问题就是出在移植到android上
#108楼 回复 引用 查看
by jerry2011
你好,我下载了源代码,然后在eclipse中导入,编译运行后,出现的窗口是黑色的,并没有图像出来,博主知道是什么原因吗?
#109楼 121.33.73.* 回复 引用
by free2010[未注册用户]
你搜一下 ffmpeg android ndk 等关键字。
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 .非常感激!
#110楼 回复 引用 查看
by 黄瓜炒鸡蛋
博主你好,是不是 你的两个码流文件分辨率都写死了,所以 在程序中 改Width 、Height分辨率并不会改变?
#111楼 116.231.116.* 回复 引用
by 本博客博主[未注册用户]
@free2010,已上传基于ffmpeg的android播放器开源代码,或许对你有点点帮助。
@黄瓜炒鸡蛋,程序显示的思想是如果原始视频图像分辨率比手机屏分辨率大,就上下左右丢边,显示中间的图像,如果比手机屏分辨率小,就居中显示,程序没有做缩放。没仔细看width,height变量的影响。
#112楼 121.32.169.* 回复 引用
by free2010[未注册用户]
@ 本博客博主
非常感激. 前进的道路有你. !
#113楼 回复 引用 查看
by 黄瓜炒鸡蛋
博主您好 非常感谢您的分享 您的解码器 是不是,只有视频处理而没有声音处理呢!如果没有,您能不能给个既可以处理视频又可以处理声音的解码器呢!
#114楼 219.141.190.* 回复 引用
by toyan[未注册用户]
刚接触android方面的开发,博主的共享很有指导性意义,用Cortex-A9运行demo发现解码720x576帧率跟不上,开始怀疑解码器是不是有问题,从ffmeg源码编译后重新封装libh264android,发现效率并没有实质性提高(解码稳定性貌似要强许多),后来又怀疑是否是绘制的问题,换成用OpenGL绘制,也没有实质性提高。跟踪后发现问题出在颜色空间转换的地方,YUV转RGB效率太低了,不转单单解码可以达到25fps,加上转换就会降一半,试了试libstagefight里的转换函数,效率一样的。真不知道mediaplayer解码怎么弄的,1080p都能解得那么流畅,郁闷啊!
#115楼 回复 引用 查看
by zk0301
android版的run()里能不能加点注释,新手看起来很吃力.比如说一些变量代表什么,函数作用是什么等等.
#116楼[楼主] 回复 引用 查看
by mcodec
run函数的基本流程是,每次从文件中读2048个字节到sockbuf缓冲区,然后在MergeBuffer()函数中一个字节一个字节的拷贝到nalbuf缓冲区并识别0x00000001开始字做nal分割,再把nalbuf中完整的nal调用DecoderNal做解码,依返回值判断是否刷屏,解码sps,pps等nal不用刷屏。
因为此开源代码是从网络播放器中删减而来,所以是sockbuf。
NalBufUsed和SockBufUsed是计数控制变量。
int mTrans=0x0F0F0F0F 为监视是否是0x00000001开始字而定义的变量,其初值尽量和0x00000001开始字不相关,可以是其他值。
或者你看一下h264的标准可能会更好的理解。
#117楼 回复 引用 查看
by zk0301
@mcodec
thank you
#118楼 回复 引用 查看
by gongmeng
为什么运行几秒后就自动关闭了呢?
#119楼[楼主] 回复 引用 查看
by mcodec
@gongmeng,原始测试文件很小,就几秒钟。
如果是你自己的测试媒体文件,那可能是其他异常,可能是nalbuf小了,或者非baseline规格,这需要仔细调试。
#120楼 113.78.59.* 回复 引用
by free2010[未注册用户]
profile:level : Baseline:2.0 能正常解
profile:level : Baseline:1.3 解码失败
请问一下.博主这是什么总是 ? 要怎么解决?
#121楼[楼主] 回复 引用 查看
by mcodec
@free2010,这个只能是debug哦,要不你发个500k左右的码流到我的邮箱[email protected]。如果有时间,我帮你看看。
#122楼 113.78.59.* 回复 引用
by free2010[未注册用户]
引用 mcodec:@free2010,这个只能是debug哦,要不你发个500k左右的码流到我的邮箱
[email protected]。如果有时间,我帮你看看。
已经发了. 请查收. 谢谢
#123楼[楼主] 回复 引用 查看
by mcodec
@free2010,经测试,貌似你的码流是用华为海思的压缩芯片编码出来的,码流怪怪的,本网站上的代码解不了。如果你们愿意付点费用,我给另外的源码给你。
#124楼 113.79.83.* 回复 引用
by free2010[未注册用户]
引用 mcodec:@free2010,经测试,貌似你的码流是用华为海思的压缩芯片编码出来的,码流怪怪的,本网站上的代码解不了。如果你们愿意付点费用,我给另外的源码给你。
谢谢. 我向公司反映一下情况
#125楼 回复 引用 查看
by zk0301
楼主你好,我又来啦.问个问题哈:
使用您的代码得到的一帧数据,可以draw到surfaceView上,实现播放.
我现在想把它保存成jpg图片存到sdcard上.
问题就是rgb的怎么转jpg的.
#126楼[楼主] 回复 引用 查看
by mcodec
@zk0301,你保存成bmp文件要简单很多,这只需要加一个简单的bmp文件头即可。
如果一定要保存成jpg文件,你用其他的库转换bmp文件到jpg也比较简单。
如果你不想写bmp文件,那你就去找jpg压缩库吧,android应该自带,但不知道接口好不好用,特别要注意rgb565,yuv等等格式的差别。
#127楼 121.227.96.* 回复 引用
by Sisyphus60[未注册用户]
请问博主,当图像快速晃动时,解码器崩溃,如何解决?期待答复
#128楼[楼主] 回复 引用 查看
by mcodec
@Sisyphus60,这个问题只能debug才能解决,你把原始码流发个1M左右到我的邮箱,[email protected],如果有时间,我帮你看一下。
你也可以在本网站下载vc6的版本,在windows下自己跟踪调试。
#129楼 回复 引用 查看
by jasonng
請問博主,
我把播放文件流改爲接受udp流做實時播放
可以實時播放了 但播了大約10秒左右 程序自動退出了
不知道是什麽原因...
期待您的答復 謝謝
剛剛看了網友也有相關的問題
您提到了檢查裸流,我查了 沒問題
然後要換解碼器? 不是很明白 要怎樣換?換哪個?
另外 我想問網絡那邊扔過來的大小 和nalbuf 的大小 是不是和這個問題有聯係?
還有讀取2048byte 似乎也不能改..
期待你的回答 謝謝
#130楼[楼主] 回复 引用 查看
by mcodec
@jasonng,
检查裸码流看是否符合baseline要求,这个主要看编码器那边打开了那些开关。
nalbuf和图像大小,带宽有关。现在是一次解码一个完整的nal单元,如果图像大,带宽大,导致nal单元大,那nalbuf也要大些,和网络包大小没什么关系。
2048是一个临时的缓冲区,大小可以改。
对应于你这种情况,我会把接受的网络码流保存成本地文件,然后用开源的播放器播,看哪个播放器能正确的播放,然后从开源代码中分离和优化解码器,换掉不能播放的解码器。
#131楼 回复 引用 查看
by jasonng
@mcodec
很感激博主的回答
我重新用了最新的ffmpeg源碼 參考你的JNI文件 重新提取了
現在10秒自動退出的問題沒有了
但是晃動劇烈時 就會卡住 並隔一會自動退出
之前有網友問了 請問現在有沒有這個問題的解決方案?
謝謝
#132楼 218.94.136.* 回复 引用
by qingtingchen[未注册用户]
博主您好,请问一下你的这个代码是否支持 接受一帧图像数-->解码-->刷新显示,这样的一个流程,找了一个和您的相似的代码,里面邮编吗和解码,我编码一帧图像之后在本地直接解码,编码出来保存的文件是可以播放的,但是解码出来的数据不正确,不知道这是什么原因,是不是不能一帧一帧地解码,谢谢
#133楼[楼主] 回复 引用 查看
by mcodec
@jasonng,你用编译原始的ffmpeg代码跑,看是否会退出,定位是原始的ffmpeg代码有问题还是自己分离移植不小心出错。如果原始的ffmpeg都有问题,那就只能换其他解码器,难度相对较大。如果原始的ffmpeg没有问题,比对一下代码,改对即可。
注意,可以多用几个原始的ffmpeg版本测试。
#134楼[楼主] 回复 引用 查看
by mcodec
@qingtingchen,解码器是一个nal一个nal的解码。如果解码器支持编码器打开的所有开关,并且是一帧图像压出来的完整数据包,肯定可以解码。
可能的检查方向,sps/pps等信息是否正确,码流数据包是否完整,编码器是否打开了解码器不支持的开关。
#135楼 回复 引用 查看
by jasonng
@mcodec
謝謝您的解答 我把具體資料發到您[email protected]郵箱了
望有空時幫我看看
#136楼 回复 引用 查看
by cruisehuang
博主提供拍照(转RGB565为bmp)和录像(包括播放、快慢进等)功能代码,谢谢![email protected].
#137楼[楼主] 回复 引用 查看
by mcodec
@cruisehuang:
拍照功能简单,bmp有rgb565格式的,只要把bmp文件头写对即可,可以在java中实现,也可以在jni层实现。
录像功能也简单,因为是在java层做的nal分割,保存好sps,pps,需要录像时,把sps和pps先写到文件,然后识别IDR帧开始录像。不过开发这部分代码需要懂一些H264标准。
快播慢播只需要修改时钟,此demo代码没有做时钟控制,最简单就是sleep函数了。
seek功能就复杂多了,要计算总时间和换算相当偏移,还要查找idr帧。
#138楼 回复 引用 查看
by jasonng
@mcodec
博主你好 不知爲何 發你的郵箱 [email protected] 發不出..
我發了站内信給你 有空幫我看看 謝謝
#139楼 回复 引用 查看
by jasonng
請問博主能否提供一原始沒刪減 且此博文代碼適用的的ffmpeg?謝
#140楼 回复 引用 查看
by jasonng
解決了 用原始ffmpeg解碼解決了 請無視我上面的問題. 謝謝博主一路以來的解答!謝謝
#141楼 回复 引用 查看
by cruisehuang
引用 mcodec:
@cruisehuang:
拍照功能简单,bmp有rgb565格式的,只要把bmp文件头写对即可,可以在java中实现,也可以在jni层实现。
录像功能也简单,因为是在java层做的nal分割,保存好sps,pps,需要录像时,把sps和pps先写到文件,然后识别IDR帧开始录像。不过开发这部分代码需要懂一些H264标准。
快播慢播只需要修改时钟,此demo代码没有做时钟控制,最简单就是sleep函数了。
seek功能就复杂多了,要计算总时间和换算相当偏移,还要查找idr帧。
能否提供一份DEMO代码至
[email protected],刚刚接触H264,很多概念比较生疏,谢谢!
#142楼 回复 引用 查看
by Mical Steve
楼主,我想问你一下,为什么我用ffmpeg解码h264流完全花屏?
#143楼 回复 引用 查看
by Mical Steve
@本博客博主
楼主,我想问你一下,为什么我用ffmpeg解码h264流完全花屏?
#144楼[楼主] 回复 引用 查看
by mcodec
@Mical Steve: 对你这个问题,如果是我,我会找JM参考代码跑一下,看是否正常,如果不正常,那就是码流出了问题,如果JM代码正常,我会用最新的ffmpeg源码在linux下编译跑一下看是否正常,如果正常,那就重新移植ffmpeg,如果不正常,那就是你的编码器打开了很生僻的开关,而此开关ffmpeg不支持。
如果JM代码正常,ffmpeg代码不正常,要不找其他开源的能正确跑的解码器,从其他的地方移植。或者debug JM的代码,看码流到底打开了什么鬼鬼开关,自己在ffmpeg代码中添加上对这个开关的支持,当然这个难度很大。
#145楼 回复 引用 查看
by Mical Steve
@mcodec
博主,为什么我用jm播放不了我的视频文件,而用vlc却能很流畅的播放我的h264文件呢?用快播也能很流畅的播放
#146楼 回复 引用 查看
by Mical Steve
@mcodec
用JM代码跑了一下,能准确的生成test_dec.yuv文件。太感激博主了...
#147楼 回复 引用 查看
by haoruifly
善良的博主大大,我在做P2P的客户端,要把一个opensvc的解码器移植到android上,看了你的博客,请教你几个问题哈:
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头文件
#148楼 回复 引用 查看
by haoruifly
还请博主方面的话 加下我的QQ,多指导下我这个菜鸟咯
QQ:407667124
#149楼[楼主] 回复 引用 查看
by mcodec
@haoruifly,
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;
#150楼 回复 引用 查看
by haoruifly
谢谢博主热心回复哈\(^o^)/~,各种感谢加\(≧▽≦)/
(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?
#151楼 回复 引用 查看
by haoruifly
另外有个笨笨的问题请教博主
(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中的改动好大啊 这里改动幅度看起来表示很吃力的说
#152楼 回复 引用 查看
by haoruifly
从H264码流中分割出Nal能不能不在在java层做,依然将其保留在h264android.c文件,用底层实现呢?这样要好读懂些?并且移植的工作量也小得多
#153楼[楼主] 回复 引用 查看
by mcodec
@haoruifly,Nal分割可以在底层做,但是这样就要在jni底层调用java层的函数,最后就是java层要调用jni层,jni层也要调用java层的双向调用,如果放在java层做,就只有java层调用jni层的单向调用,单向调用貌似直观一些。
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文件删除了。
#154楼 回复 引用 查看
by haoruifly
谢谢博主的回复O(∩_∩)O哈哈~
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接口文件?
#155楼 回复 引用 查看
by haoruifly
我的油箱号:[email protected],麻烦博主给我发一份生成.h文件吧
#156楼 回复 引用 查看
by haoruifly
博主 ,网上有说参考framework/base/media/libstagefright/codes,封装实现start、stop、read三个接口就可以,还有的说移植解码库,只要移植opencore就行,这个不太理解,移植解码库是不是写native接口函数,按照jni调用的方式就行了吧
#157楼[楼主] 回复 引用 查看
by mcodec
@haoruifly,此demo是在jni底层做解码,在java层做界面刷新。在java做nal分隔,可以依据解码函数的返回值判断是否刷视频。如果把nal分割放到jni底层做,底层解码后要通知界面刷新视频,只能用jni层调用java层函数实现通知刷视频的功能,此demo为避免此类调用所以在java层做nal分割,所以你看不到jni层调用java层的东西。
当然,你也可以在jni层直接输出视频,本blog有相关示例,这样jni层就不用调用java层了。
现在一直没有调用javah生成.h文件了,都是直接拼接出jni函数名,你可以看一下网上jni方面的文章,一大把。
记忆中定义好接口函数后,编译一下,再调用javah生成.h文件,不用补齐.java文件。
#158楼 回复 引用 查看
by haoruifly
恩 谢谢博主,对我来说最难的不是用javah生成.h文件,而是随便给我一个开源库的main.c,按照博主的三个接口函数,一个初始化函数,一个功能函数,一个反初始化函数,感觉java的函数接口是最难选择的 其次参考main.c.old文件写个.c文件实现.h文件声明的函数,这两块各种难啊
#159楼[楼主] 回复 引用 查看
by mcodec
@haoruifly,以我目前的知识,理解的意思是,封装实现start,stop,read三个函数貌似是写libstagefright插件,那就要遵守libstagefright的一些规则,由系统自动调用。当然如果有足够的水平,参照系统的播放器自己也可以写一个播放器,自己调用编解码库。
如果要系统自动调用,就要编译系统,烧录rom之类的工作,普通的应用程序不应该烧录rom。
如果自己写一个播放器,然后自己调用编解码库,工作量不可小视。
此demo完全脱离android自带的libstagefright和opencore架构,除了音视频输出的效率不是特高外,基本上是最简单最容易的实现方案。
#160楼 回复 引用 查看
by haoruifly
O(∩_∩)O哈哈~ 博主在线啊
请问博主能否在推荐个开源的代码 让咱能感受下 接口函数的选取 及在.java中的native声明和在.c中的实现的代码,以我现在的知识对照着博主这个改写opensvc还是很有困难的
#161楼 回复 引用 查看
by haoruifly
也就是所短期时间内 还是按照jni接口的方法移植解码库相当来说 好上手些 嘿嘿 谢谢善良的博主大大的热心回复O(∩_∩)O哈哈~
#162楼 回复 引用 查看
by haoruifly
我看了那个jni层直接输出视频的代码,在.java中nativePlay()是接口函数,可是在FFMpegPlayerAndroid.cpp中既没有找到这个接口函数的代码的实现部分,也没有在头文件中包含#include
还有就是不但木有找到接口函数nativePlay()的实现代码,怎么又把不是接口函数的两个函数jniRegisterNativeMethods()和 FFMpegPlayerAndroid_play()也按照jni的格式写了?
我看在H264Android.c中只是对接口函数按照jni的格式给实现了,并没有实现DeleteYUVTab(), DisplayYUV_16之类的非接口函数代码?
对比着看FFMpegPlayerAndroid.cpp和H264Android.c,我对jni接口函数的选取和参考main.c.old文件写个.c文件实现.h文件声明的函数更加疑惑
#163楼 回复 引用 查看
by haoruifly
对了博主 对于一个开源库移植android和软件或者C写的客户端什么的移植android有什么区别吗?
#164楼[楼主] 回复 引用 查看
by mcodec
@haoruifly,nativePlay和ffplayAndroid_play是在static JNINativeMethod methods[]数据结构中关联在一起,调用jniRegisterNativeMethods函数注册后,可以简单认为这两函数是同一个函数。
h264android.c中的视频输出是在java层用bmp序列函数实现的,所以要有DeleteYUVTab()等yuv到rgb565转换的相关函数。
ffplay中的视音频输出是调用libffplay.so库中的函数直接在jni层输出,yuv到rgb的转换在libswscale子目录下的函数中已经实现了,不用再做转换所以看不到DeleteYUVTab()等函数。
#165楼 回复 引用 查看
by haoruifly
对了 博主,这个移植前的H264解码库的对外头文件是哪个,也就是说移植前库所暴露的接口是什么
#166楼 192.84.19.* 回复 引用
by yyc1201[未注册用户]
我用博主的解码, 确实会整个萤幕消失崩溃, 经过我努力debug, 每次运行到h264.c里的decode_mb_cavlc, 就会整个萤幕消失, 这个decode_mb_cavlc很大, 很难具体再debug出到底哪一个细节造成crash, 这个decode_mb_cavlc如果移除, 就不会有萤幕退出的问题, 博主觉得是什么问题吗? 我是用Rtp Socket收Rtp Packet去解码的, 当收到有marker bit=1的Rtp Packet去重建一个frame(每个Nal都各加了4 bytes header), 然后把新建好的frame buffer去解码就崩溃, 感谢博主赐教!
#167楼 115.154.191.* 回复 引用
by Rora[未注册用户]
楼主,十分感谢你的代码,我在应用中使用了你的代码,静态图象不成问题,只是视频一旦运动,就会出现花屏,您知道是怎么回事吗?应当如何修改您的代码?
#168楼[楼主] 回复 引用 查看
by mcodec
@tinystone_1116,花屏的问题要仔细的跟踪调试,目前没有太多的时间去做这个方面的事情。如果你要修改代码,至少得把h264的标准看差不多懂,这份代码看差不多懂,或许还要把jm的参考代码看差不多懂,然后这个代码和jm代码单步调试,对比看运行时的差别,找到花屏的原因,在对症修改。
#169楼 114.249.236.* 回复 引用
by 鲁志慧[未注册用户]
博主,你好,我想请问一下像rtmp://media3.sinovision.net:1935/live/livestream或者rtsp://media3.sinovision.net:1935/live/livestream这样的视频流怎样调用播放?
#170楼[楼主] 回复 引用 查看
by mcodec
@鲁志慧,这个版本不支持流媒体播放。
貌似android直接支持rtsp协议,但好像不好用,ffmpeg是直接支持rtmp和rtsp协议的,但需要重新移植。
如果仅仅只支持rtsp协议,移植live555也可以。
#171楼 101.68.66.* 回复 引用
by 哈维[未注册用户]
博主,你好!请问如果想让该工程播放出main档次或high档次编码出来的264文件,应该如何修改或者改进?
#172楼 回复 引用 查看
by yisanmao
02-13 11:53:55.057: ERROR/InputDispatcher(131): channel '408967c8 h264.com/h264.com.H264Android (server)' ~ Consumer closed input channel or an error occurred. events=0x8
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文件,测试出现这个问题,请问楼主怎么解决?????