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应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于 ...
随机推荐
- css sprite的实现
css sprite 为什么使用css sprite? 网页上的非常多静态小图片在载入时须要大量http请求,添加了响应时间.(哈哈.雅虎34条优化法则的第一条啊) css的background-po ...
- Android 中View的绘制机制源代码分析 二
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要解说 ...
- 百度编辑器图片在线流量返回url改动
百度编辑器中返回的是我们server中的url,有时并非我们须要的,比方图文编辑中.我想在线浏览上传过的图片 ,那么我返回的应该是腾讯server上面的url.这样才不会被腾讯的过滤器过来掉,全部我们 ...
- BZOJ 2733 线段树的合并 并查集
思路: 1.线段树合并(nlogn的) 2.splay+启发式合并 线段树合并比较好写 我手懒 //By SiriusRen #include <cstdio> #include < ...
- 入门 IT 行业,该具备哪些技能?
对于刚开始进入IT的新人来说,“必备技能”往往意味着一个长长的.标有重要度的学习列表,但是过长的列表通常会导致新人不知如何开始学习,压力倍增.本文尝试列举出最重要的几个技能,也期望通过此列表能给新人一 ...
- Java NIO(七)管道
Java NIO 管道是两个线程之间的单向数据连接.Pipe有一个source通道和sink通道(内部类).数据会被写到sink通道,从source通道读取. 给一张Pipe通道的原理图: 创建管道: ...
- function——函数声明头的提升和预解析
函数: 即function语句的集合,就是将多个语句封装到一起: 函数的执行要会自己遍历,遇见函数 a():执行语句,就要移交控制权,函数执行完毕之后,控制权又移交回来了! 函数的参数要罗列在func ...
- Oracle 合并查询
8).合并查询有时在实际应用中,为了合并多个select语句的结果,可以使用集合操作符号union,union all,intersect,minus.多用于数据量比较大的数据局库,运行速度快.1). ...
- Servlet的生命周期和Jsp的生命周期
Servlet的生命周期: 1)构造方法(第1次访问) 2)init方法(第1次访问) 3)service方法 4)destroy方法 Jsp的生命周期 1)翻译: jsp->java文件 2) ...
- centos7下安装pyspark
1.安装python 2.安装jdk 3.下载spark:http://spark.apache.org/downloads.html, 下载新版(spark-2.3.1-bin-hadoop2.7. ...