今天在使用android-as_video_player这个开源的框架来实现自己项目中的一个播放器,中间关于ndk编译ffmpeg遇到的坑,现在想起来,对ndk的心态,现在心里都有一万个cnm在奔腾,此处略过ndk编译ffmpeg源码的过程,最后使用的ndk-r10d编译的ffmpeg2.8.5版本。其实这时候ffmpeg已经更新到了4.1版本,要求别这么多,先将就着作用。
第一个坑就是当我把代码码完了,lib也编译通过,程序也能调试了的时候,心里是愉悦的,但跑起来以后,运行不正常,本地文件视频播放不出来,这就很尴尬了哈。
然后通过接口观察数据,发现avformat_open_input这个接口失败了,然后呢?报错信息调试为:Invalid data found when processing input,于是百度,谷歌搜索一番先,然后大部分人说调用的lib被协议部分被禁用的原因,于是就有了自己ndk编译ffmpeg这么操蛋的事情发生了。可我自己编译的lib怎么也不行呢?搞了半天,没办法,自己先阅读一通ffmpeg源码,然后发现还是找不到问题,于是想起来,我可以给ffmpeg设置一个log的回调函数,然后把错误信息报错的更加详细一些,于是加log回调函数,然后获取报错信息: moov atom not found,然后又baidu,google一番,少有收获哈,在https://bbs.csdn.net/topics/300243359论坛上找到第一条有用的信息。
原因是lseek函数在custom的接口中实现的有问题。
而从ffmpeg的源码,我们获取这个报错的信息位置为:
因为mp4文件,moov在文件的末尾,所以这个地方可以判断可能真的是lseek的原因。
然后加断点,发现我写的seek函数在whence等于AVSEEK_SIZE的时候,返回的-1。那custom方式的seek到底怎么实现呢?
经过参考http://www.52ffmpeg.com/article/497.html和https://www.codeproject.com/Tips/489450/Creating-Custom-FFmpeg-IO-Context这两个文件,AVSEEK_SIZE这whence应该是返回文件的大小,同时seek我们也可以参考代码自己实现一个;
于是我自己的实现方式:
1 int FileSource::ReadSeek( int offset, int whence){ 2 // 参数检查. 3 int ret=-1; 4 if (offset > m_nFileSize || !m_file.is_open()){ 5 LOGI("seek offset=%d> file size:%d,or file is close.",offset,m_nFileSize); 6 return -1; 7 } 8 if (m_bIsMultithread) 9 m_mutex.Lock(); 10 11 std::ios_base::seekdir way = (std::ios_base::seekdir)whence; 12 // 进行seek操作. 13 if (whence != AVSEEK_SIZE) { 14 //先把错误位置给 15 m_file.clear(); 16 ////////////////////////////// 17 switch(whence){ 18 case SEEK_SET: 19 //基于文件开始位置进行seek跳转 20 m_file.seekg(offset,std::ios_base::beg); 21 // ret = offset; 22 break; 23 case SEEK_CUR: 24 //基于文件当前位置进行seek跳转 25 m_file.seekg(offset,std::ios_base::cur); 26 // ret=m_file.tellg(); 27 break; 28 case SEEK_END: 29 //基于文件尾的位置进行seek跳转 30 m_file.seekg(offset,std::ios_base::end); 31 // ret=m_file.tellg(); 32 break; 33 } 34 if (m_file.good()) 35 ret = m_file.tellg(); 36 else 37 ret = -1; 38 }else{ 39 //等于AVSEEK_SIZE,这个主要是用于获取文件大小 40 // The whence-parameter has one more option than fseek: AVSEEK_SIZE. 41 // When this option is passed to the seek function it should return the file size (if possible). 42 // If its not possible, the function may return and do nothing -1. In my implementation pStream->Seek(...) will fail with AVSEEK_SIZE and SeekFunc will return -1. 43 ret=m_nFileSize; 44 } 45 46 if (m_bIsMultithread) 47 m_mutex.Unlock(); 48 49 return ret; 50 }
然后,视频就能正常解码和播放了
转载请注明出处:https://www.cnblogs.com/lihaiping/p/10637615.html