ffmpeg在android上输出滑屏问题处理
ffmpeg部分机器上有花屏的问题
原代码例如以下:
while(av_read_frame(formatCtx, &packet)>=0 && !_stop && NULL!=window && bInit) {
// Is this a packet from the video stream?
if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video2(codecCtx, decodedFrame, &frameFinished,
&packet);
// Did we get a video frame?
if(frameFinished) {
// Convert the image from its native format to RGBA
sws_scale
(
sws_ctx,
(uint8_t const * const *)decodedFrame->data,
decodedFrame->linesize,
0,
codecCtx->height,
frameRGBA->data,
frameRGBA->linesize
); if(packet.dts == AV_NOPTS_VALUE
&& decodedFrame->opaque && *(uint64_t*)decodedFrame->opaque != AV_NOPTS_VALUE)
{
pts = *(uint64_t *)decodedFrame->opaque;
LOGD("pst1: %d",pts);
}
else if(packet.dts != AV_NOPTS_VALUE) {
pts = packet.dts;
LOGD("pst2: %d",pts);
} else {
pts = 0;
LOGD("pst3: %d",pts);
}
//pts = av_q2d(codecCtx->time_base) * 1000000.0 * i * 2;
pts *= 1000;
//LOGD("debug %d,%d,%f",pts, (long)(av_q2d(codecCtx->time_base) * 1000000.0 * i * 2), av_q2d(codecCtx->time_base));
if(0 == pts || 0 == baseTime)
{
baseTime = av_gettime() - pts;
LOGD("BASETIME: %d",baseTime);
}else{
waitTime = (baseTime + pts) - av_gettime();
LOGD("WAITTIME: %d, %d",waitTime,pts);
} //waitTime = (av_q2d(codecCtx->time_base) * 1000.0 - 0.0) * 1000;
if(waitTime>0)
usleep(waitTime);
if(!_stop)
{
synchronized(lockWindow)
{
if(!_stop && NULL!=window)
{
// lock the window buffer
if (ANativeWindow_lock(pWin, &windowBuffer, NULL) < 0) {
LOGE("cannot lock window");
} else {
// draw the frame on buffer
//LOGD("copy buffer %d:%d:%d", width, height, width*height*RGB_SIZE);
//LOGD("window buffer: %d:%d:%d", windowBuffer.width, windowBuffer.height, windowBuffer.stride);
memcpy(windowBuffer.bits, buffer, width * height * RGB_SIZE);
// unlock the window buffer and post it to display
ANativeWindow_unlockAndPost(pWin);
// count number of frames
++i;
}
}
}
}
}
}
细致分析后发现 部分分辨率又可以正常展示,感觉是宽度错位导致的,分析例如以下:
ORG: 176 * 144 F
X2: 352 288 O
X3: 528 432 F
X4: 704 576 O
X6: 1056 * O
X1.1 193 158 F
X1.2 211 172 F
X1.5 264 216 F
X0.5 88 72 F
X2?
: 352 290 O
X2?: 352 600 O
X2?: 352 720 O
X4?: 704 720 O
X6?: 1056 720 O
1280 ---1312
1056
1184
1248 ok
发现分辨率依照%64+32对齐, 感觉是内存对齐造成的, 查看ANativeWindow_Buffer例如以下
typedef struct ANativeWindow_Buffer {
// The number of pixels that are show horizontally.
int32_t width; // The number of pixels that are shown vertically.
int32_t height; // The number of *pixels* that a line in the buffer takes in
// memory. This may be >= width.
int32_t stride; // The format of the buffer. One of WINDOW_FORMAT_*
int32_t format; // The actual bits.
void* bits; // Do not touch.
uint32_t reserved[6];
} ANativeWindow_Buffer;
输出stride和width的日志发现,假设正常显示则stride==width, 通过凝视能够看出应该是内存对齐问题导致的,调整代码:
if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video2(codecCtx, decodedFrame, &frameFinished,
&packet);
// Did we get a video frame? if(frameFinished) {
// Convert the image from its native format to RGBA
sws_scale
(
sws_ctx,
(uint8_t const * const *)decodedFrame->data,
decodedFrame->linesize,
0,
codecCtx->height,
frameRGBA->data,
frameRGBA->linesize
); if(packet.dts == AV_NOPTS_VALUE
&& decodedFrame->opaque && *(uint64_t*)decodedFrame->opaque != AV_NOPTS_VALUE)
{
pts = *(uint64_t *)decodedFrame->opaque;
LOGD("pst1: %d",pts);
}
else if(packet.dts != AV_NOPTS_VALUE) {
pts = packet.dts;
LOGD("pst2: %d",pts);
} else {
pts = 0;
LOGD("pst3: %d",pts);
}
//pts = av_q2d(codecCtx->time_base) * 1000000.0 * i * 2;
pts *= 1000;
//LOGD("debug %d,%d,%f",pts, (long)(av_q2d(codecCtx->time_base) * 1000000.0 * i * 2), av_q2d(codecCtx->time_base));
if(0 == pts || 0 == baseTime)
{
baseTime = av_gettime() - pts;
LOGD("BASETIME: %d",baseTime);
}else{
waitTime = (baseTime + pts) - av_gettime();
LOGD("WAITTIME: %d, %d",waitTime,pts);
} //waitTime = (av_q2d(codecCtx->time_base) * 1000.0 - 0.0) * 1000;
if(waitTime>0)
usleep(waitTime);
if(!_stop)
{
synchronized(lockWindow)
{
if(!_stop && NULL!=window)
{
// lock the window buffer
if (ANativeWindow_lock(pWin, &windowBuffer, NULL) < 0) {
LOGE("cannot lock window");
} else {
// draw the frame on buffer
//LOGD("copy buffer %d:%d:%d", width, height, width*height*RGB_SIZE);
//LOGD("window buffer: %d:%d:%d", windowBuffer.width, windowBuffer.height, windowBuffer.stride);
//memcpy(windowBuffer.bits, buffer, width * height * RGB_SIZE);
if(windowBuffer.width >= windowBuffer.stride){
memcpy(windowBuffer.bits, buffer, width * height * RGB_SIZE);
}else{
//skip stride-width 跳过padding部分内存
for(int i=0;i<height;++i)
memcpy(windowBuffer.bits + windowBuffer.stride * i * RGB_SIZE
, buffer + width * i * RGB_SIZE
, width * RGB_SIZE);
}
// unlock the window buffer and post it to display
ANativeWindow_unlockAndPost(pWin);
// count number of frames
++i;
}
}
}
}
}
}
通过行拷贝方式,跳过后面对齐部分的内存,
解决这个问题,
ffmpeg在android上输出滑屏问题处理的更多相关文章
- FFmpeg在Android上的移植之第一步
http://blog.sina.com.cn/s/blog_69a04cf40100x1fr.html 从事多媒体软件开发的人几乎没有不知道FFmpeg的,很多视频播放器都是基于FFmpeg开发的. ...
- FFmpeg在Android上的移植优化步骤
http://blog.csdn.net/feixiang_john/article/details/7894188 从事多媒体软件开发的人几乎没有不知道FFmpeg的,很多视频播放器都是基于FFmp ...
- android 添加左右滑屏手势
今天要在自己的项目中添加左右滑动,实现日期的加减(原来已经做了加减按键).滑动在一个中间的layout中进行 思路:添加左右划屏幕判断,得到判断后模拟加减按键按下. 模拟按键按下用 mbotton.p ...
- 【Android 界面效果29】研究一下Android滑屏的功能的原理,及scrollTo和scrollBy两个方法
Android中的滑屏功能的原理是很值得我们去研究的,在知道这两个原理之前,有必要先说说View的两个重要方法,它们就是scrollTo 和scrollBy. Android View视图是没有边界的 ...
- Android之滑屏动画和自定义控件
滑屏动画 在Android系统中,通过手势识别切换界面时,通常会在界面切换时加入动画,以提高用户的体验效果,这种动画一般都采用平移动画,下一个界面进入时,上一个界面移除屏幕. 图中标识的均为左上角坐标 ...
- (转)【移动开发】Android中三种超实用的滑屏方式汇总(ViewPager、ViewFlipper、ViewFlow)
转自: http://smallwoniu.blog.51cto.com/3911954/1308959 现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习 ...
- Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解
前言: 虽然本文标题的有点标题党的感觉,但无论如何,通过这篇文章的学习以及你自己的实践认知,写个简单的滑屏小 Demo还是just so so的. 友情提示: 在继续往下面读之前,希望您对以下知识点 ...
- Android中滑屏初探 ---- scrollTo 以及 scrollBy方法使用说明
今天给大家介绍下Android中滑屏功能的一个基本实现过程以及原理初探,最后给大家重点讲解View视图中scrollTo 与 scrollBy这两个函数的区别 . 首先 ,我们必须明白在Android ...
- Android中三种超实用的滑屏方式汇总(转载)
Android中三种超实用的滑屏方式汇总 现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于 ...
随机推荐
- windows、linux劫持技术
windows系统以下能够利用detours劫持 realse 模式劫持,调试的程序不能够 函数劫持能够实现的效果. 函数的劫持原理 我们怎样实现-detours detours是微软亚洲研究院出品 ...
- Codeforces 558B Amr and The Large Array
B. Amr and The Large Array time limit per test 1 second memory limit per test 256 megabytes input st ...
- JavaScript——BOM(浏览器对象模型),时间间隔和暂停
BOM(浏览器对象模型):能够对浏览器的窗体进行訪问和操作 1.主要的BOM体系: window------------document-------------------------------- ...
- UESTC--1271--Search gold(贪心)
Search gold Time Limit: 1000MS Memory Limit: 65535KB 64bit IO Format: %lld & %llu Submit Sta ...
- hdoj--2122--Ice_cream’s world III(克鲁斯卡尔)
Ice_cream's world III Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- BZOJ 3230 后缀数组+ST
思路: 首先我们已经会了后缀数组求本质不同的子串个数 这道题跟那个差不多 首先我们可以知道按字典序排好的每个后缀之前包含多少本质不同的字串 就是sigma(n-sa[i]+1-ht[i]+bi[i-1 ...
- BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP
终于是道中文题了.... 当时考试的时候就考的这道题.... 果断GG. 思路: 因为有可能存在依赖环,所以呢 先要tarjan一遍 来缩点. 随后就进行一遍树形DP就好了.. x表示当前的节点.j表 ...
- android编译ffmpeg+x264
下载最新版的x264ftp://ftp.videolan.org/pub/videolan/x264/snapshots/1.解压到指定的目录2.切换当前目录为该目录3.创建一个shell脚本buil ...
- EXCEL 表格保护破解
'Alt + F11 进入vb编辑器,插入代码,然后在宏查看器里执行,大概等1-2分钟,完成. Public Sub AllInternalPasswords() ' Breaks workshe ...
- WCF(三)IIS寄宿
WCF常用的一种使用方式是寄宿在IIS中. IIS寄宿操作流程如下: 1.创建IIS物理路径对应的文件夹,文件夹名称是WCFIIS. 2.在WCFIIS文件夹中添加文本文件,在文本文件中写入<% ...