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上输出滑屏问题处理,布布扣,bubuko.com

时间: 2024-10-12 07:35:49

ffmpeg在android上输出滑屏问题处理的相关文章

Android中左右滑屏实现

在网上搜索了下滑屏的实现,自己整理了下, 代码如下: package kexc.scroll; import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.V

Android中三种超实用的滑屏方式汇总(转载)

Android中三种超实用的滑屏方式汇总 现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于前段时间项目的需要,所以也对其研究了一下,总的来说滑屏实现有三种方式:(至于其他的实现方式目前后还没碰到...) 1.ViewPager 2.ViewFlipper 3.ViewFlow 一.ViewPager 官方文档介绍:http://developer.android.com/reference/

【移动开发】Android中三种超实用的滑屏方式汇总(ViewPager、ViewFlipper、ViewFlow)

现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于前段时间项目的需要,所以也对其研究了一下,总的来说滑屏实现有三种方式:(至于其他的实现方式目前后还没碰到...) 1.ViewPager 2.ViewFlipper 3.ViewFlow   一.ViewPager 官方文档介绍:http://developer.android.com/reference/android/support/v4/

Android中滑屏初探 ---- scrollTo 以及 scrollBy方法使用说明

本文原创 ,转载必须注明出处 :http://blog.csdn.net/qinjuning 今天给大家介绍下Android中滑屏功能的一个基本实现过程以及原理初探,最后给大家重点讲解View视图中scrollTo 与 scrollBy这两个函数的区别 . 首先 ,我们必须明白在Android View视图是没有边界的,Canvas是没有边界的,只不过我们通过绘制特定的View时对 Canvas对象进行了一定的操作,例如 : translate(平移).clipRect(剪切)等,以便达到我们的

Android中滑屏实现----触摸滑屏以及Scroller类详解 .

转:http://blog.csdn.net/qinjuning/article/details/7419207 知识点一:  关于scrollTo()和scrollBy()以及偏移坐标的设置/取值问题 scrollTo()和scrollBy()这两个方法的主要作用是将View/ViewGroup移至指定的坐标中,并且将偏移量保存起来.另外: mScrollX 代表X轴方向的偏移坐标 mScrollY 代表Y轴方向的偏移坐标 关于偏移量的设置我们可以参看下源码: package com.qin.

Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解

Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解

关于移动端开发时iOS上滑屏卡顿的问题,以及电话类数字的样式失控问题

写在前面的话: tips:写移动的时候,那些头部需要固定显示在显示屏顶部的,通常在PC端我会用fixed来写.但是,在移动端,这并不是一个好方法,因为弹出输入小键盘的时候,会造成fixed 的元素偏移掉,在这里有两种方法可以解决: 1.建议移动端布局采用以下方式(见正文),如果有错误的地方,还请指正~ 2.另外还看到一篇文章提到这个问题,作者让固定的头部仍然采用fixed, 然后内容区也用了fixed,内容区的fixed元素这样写:{position:fixed;top:80px;bottom:

你的Android手机能投屏到电脑上吗?方法我都给你列出来了

共享屏幕正在一步一步的进入到我们的生活中,从最原始的手机-电视屏幕共享到现在的手机-电脑屏幕共享,这一规模正在逐步的扩散至全球的各个角落中,随之的手机型号的不同,从symbian-Windows phone-Firefox OS-Android.iOS,这些型号一代又一代的被淘汰,如今市面上最大的两个手机巨头就是Android和iOS. 你的手机可以投屏到电脑上吗?你的手机能投屏到电脑上吗?面对这样的问题,你们的回答是什么呢? 以下是Android与iOS投屏到电脑上的方法,Android与iO

Android左右滑动滚屏的实现

现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于前段时间项目的需要,所以也对其研究了一下,总的来说滑屏实现有三种方式:(至于其他的实现方式目前后还没碰到...) 1.ViewPager 2.ViewFlipper 3.ViewFlow   一.ViewPager 官方文档介绍:http://developer.android.com/reference/android/support/v4/