Android 补间动画原理

article/2025/11/7 23:48:24

这段时间项目中用到了动画,所以趁热打铁,看看动画原理

补间动画

使用举例

TranslateAnimation translateAnim = new TranslateAnimation(0, 100, 0, 100);translateAnim.setDuration(1000);translateAnim.setFillAfter(true);testBut.startAnimation(translateAnim)

源码分析

public void startAnimation(Animation animation) {animation.setStartTime(Animation.START_ON_FIRST_FRAME);setAnimation(animation);invalidateParentCaches();invalidate(true);}protected void invalidateParentCaches() {if (mParent instanceof View) {((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED;}}
    invalidate(true);
    invalidateParentCaches();
    方法中可以看到为当前该view的parent,就是所在的 viewgroup的标志为设置了PFLAG_INVALIDATED。所以viewgroup发生了重绘,这里为什么会这样值得深入研究进一步分析?
    
    invalidateParentCaches();
    invalidate(true);//这样很明显只是导致了该view的重绘
    为什么这样导致了view所在viewgroup的重绘    
    
首先调用

	public void draw(Canvas canvas) {// Step 1, draw the background, if neededdrawBackground(canvas);// Step 3, draw the contentonDraw(canvas);            // Step 4, draw the childrendispatchDraw(canvas);// Step 6, draw decorations (foreground, scrollbars)onDrawForeground(canvas);}
    所以可以得出结论,如果对viewgroup下的任何一个view执行动画,那么都会导致view执行整个绘制流程,不相信的话,可以自定义一个viewgroup然后重写
    draw(canvas),onDraw(canvas),dispatchDraw(canvas)方法在里面打印log
    
    这里关键的是步骤4,dispatchDraw(canvas);会去绘制子view
    
    ViewGroup类中的方法
	protected void dispatchDraw(Canvas canvas) {........for (int i = 0; i < childrenCount; i++) {while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {final View transientChild = mTransientViews.get(transientIndex);if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||transientChild.getAnimation() != null) {more |= drawChild(canvas, transientChild, drawingTime);}transientIndex++;if (transientIndex >= transientCount) {transientIndex = -1;}}int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;final View child = (preorderedList == null)? children[childIndex] : preorderedList.get(childIndex);if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {more |= drawChild(canvas, child, drawingTime);}}.......}
只要子view可见或者子view设置了动画,那么就会对该子view调用drawChild(canvas, child, drawingTime)

protected boolean drawChild(Canvas canvas, View child, long drawingTime) {return child.draw(canvas, this, drawingTime);}
回到View中的draw带三个参数的重载方法,注意区别于draw(canvas)重载方法

boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {..........Transformation transformToApply = null;boolean concatMatrix = false;final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;final Animation a = getAnimation();//首先获取当前view的动画if (a != null) {more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);concatMatrix = a.willChangeTransformationMatrix();if (concatMatrix) {mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;}transformToApply = parent.getChildTransformation();//获取的Transformation对象,包含动画矩阵}..........if (!drawingWithRenderNode || transformToApply != null) {restoreTo = canvas.save();//保存该canvas}..........if (transformToApply != null) {..........if (concatMatrix) {if (drawingWithRenderNode) {renderNode.setAnimationMatrix(transformToApply.getMatrix());} else {// Undo the scroll translation, apply the transformation matrix,// then redo the scroll translate to get the correct result.canvas.translate(-transX, -transY);canvas.concat(transformToApply.getMatrix());//为该canvas画布应用了该动画矩阵canvas.translate(transX, transY);}parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;}float transformAlpha = transformToApply.getAlpha();if (transformAlpha < 1) {alpha *= transformAlpha;parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;}}..........}..........if (restoreTo >= 0) {canvas.restoreToCount(restoreTo);//恢复到之前状态的canvas,所以并不会影响到其它子view的绘制,即使他们使用的都是viewgroup传递下来的画布}}
    Transformation对象中包含一个矩阵和 alpha 值,矩阵是用来做平移、旋转和缩放动画的。
    
    1. 视图层的绘制都是共用一个画布canvas,其实都是在最底层的decorview在viewrootimpl中创建的。
     viewgroup中的子view对canvas进行操作,并不会影响到其它子view还有该viewgroup,因为可以在draw(Canvas canvas, ViewGroup parent, long drawingTime)看到
    每绘制一个子view,都会先对画布状态进行保存save(),然后绘制完该子view之后。又会恢复restore(),所以如果在任何一个子view的onDraw(canvas)对canvas进行操作都不会
    影响到所在的viewgroup和同级的其他子view,但是如果该view是viewgroup,会影响到其所有的子view的绘制,见第二点分析

    
    2. 如果 重写viewgroup的onDraw(canvas)方法,然后对该画布进行translate,concat等操作,就会影响到整个子view的绘制
      // Step 3, draw the content
      onDraw(canvas);            
      // Step 4, draw the children
      dispatchDraw(canvas);
    可以看到绘制该viewgroup过程中, 是先调用onDraw(canvas)绘制其内容,然后绘制子view,而默认的onDraw(canvas)又是一个空实现,没有进canvas进行保存还原的操作,
    所以导致viewgroup的onDraw(canvas)方法,然后对该画布进行translate,concat等操作,就会影响到整个子view的绘制

    
    
    回到动画上的分析来,关键调用了applyLegacyAnimation(parent, drawingTime, a, scalingRequired);

	 /*** Utility function, called by draw(canvas, parent, drawingTime) to handle the less common* case of an active Animation being run on the view.*/private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,Animation a, boolean scalingRequired) {Transformation invalidationTransform;final int flags = parent.mGroupFlags;final boolean initialized = a.isInitialized();if (!initialized) {a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);onAnimationStart();}final Transformation t = parent.getChildTransformation();boolean more = a.getTransformation(drawingTime, t, 1f);if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {if (parent.mInvalidationTransformation == null) {parent.mInvalidationTransformation = new Transformation();}invalidationTransform = parent.mInvalidationTransformation;a.getTransformation(drawingTime, invalidationTransform, 1f);} else {invalidationTransform = t;}.............}
    final Transformation t = parent.getChildTransformation();
    boolean more = a.getTransformation(drawingTime, t, 1f);//操作Transformation对象t
    这两行是关键
    
    所以进入Animation的getTransformation方法

	public boolean getTransformation(long currentTime, Transformation outTransformation) {if (mStartTime == -1) {mStartTime = currentTime;}final long startOffset = getStartOffset();final long duration = mDuration;float normalizedTime;if (duration != 0) {normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /(float) duration;} else {// time is a step-change with a zero durationnormalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;}final boolean expired = normalizedTime >= 1.0f;mMore = !expired;if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {if (!mStarted) {fireAnimationStart();mStarted = true;if (USE_CLOSEGUARD) {guard.open("cancel or detach or getTransformation");}}if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);if (mCycleFlip) {normalizedTime = 1.0f - normalizedTime;}final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);//获取一个0-1的值applyTransformation(interpolatedTime, outTransformation);}.........return mMore;}
    final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);//插值器最终返回一个0-1的值
    applyTransformation(interpolatedTime, outTransformation);//然后用这个0-1的值,应用到Transformation对象上去
    TranslateAnimation动画调用Transformation对象的setTranslate,RotateAnimation调用Transformation对象的setRotate。。。。

    public Animation() {ensureInterpolator();}protected void ensureInterpolator() {if (mInterpolator == null) {mInterpolator = new AccelerateDecelerateInterpolator();}}public void setInterpolator(Interpolator i) {mInterpolator = i;}
    所以,默认情况下是AccelerateDecelerateInterpolator加速减速插值器
    
    Animation中applyTransformation默认是一个空实现,interpolatedTime是一个0-1的值
    protected void applyTransformation(float interpolatedTime, Transformation t) {}//TranslateAnimation中实现@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {float dx = mFromXDelta;float dy = mFromYDelta;if (mFromXDelta != mToXDelta) {dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);}if (mFromYDelta != mToYDelta) {dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);}t.getMatrix().setTranslate(dx, dy);}//RotateAnimation中实现@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime);float scale = getScaleFactor();if (mPivotX == 0.0f && mPivotY == 0.0f) {t.getMatrix().setRotate(degrees);} else {t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale);}}
其实最终目的都是操作Transformation t对象,其实这个对象就是上文中的,transformToApply对象。
在绘制子view过程中canvas.concat(transformToApply.getMatrix());

自定义补间动画

public class Rotate3dAnimation extends Animation {private final float mFromDegrees;private final float mToDegrees;private final float mCenterX;private final float mCenterY;private final float mDepthZ;private final boolean mReverse;private Camera mCamera;/*** Creates a new 3D rotation on the Y axis. The rotation is defined by its * start angle and its end angle. Both angles are in degrees. The rotation * is performed around a center point on the 2D space, definied by a pair * of X and Y coordinates, called centerX and centerY. When the animation * starts, a translation on the Z axis (depth) is performed. The length * of the translation can be specified, as well as whether the translation * should be reversed in time. ** @param fromDegrees the start angle of the 3D rotation * @param toDegrees the end angle of the 3D rotation * @param centerX the X center of the 3D rotation * @param centerY the Y center of the 3D rotation * @param reverse true if the translation should be reversed, false otherwise */public Rotate3dAnimation(float fromDegrees, float toDegrees,float centerX, float centerY, float depthZ, boolean reverse) {mFromDegrees = fromDegrees;mToDegrees = toDegrees;mCenterX = centerX;mCenterY = centerY;mDepthZ = depthZ;mReverse = reverse;}@Overridepublic void initialize(int width, int height, int parentWidth, int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);mCamera = new Camera();}@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {final float fromDegrees = mFromDegrees;float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);final float centerX = mCenterX;final float centerY = mCenterY;final Camera camera = mCamera;final Matrix matrix = t.getMatrix();camera.save();if (mReverse) {camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);} else {camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));}camera.rotateY(degrees);camera.getMatrix(matrix);camera.restore();matrix.preTranslate(-centerX, -centerY);matrix.postTranslate(centerX, centerY);}
}  
重写applyTransformation 函数,interpolatedTime 就是 getTransformation 函 数传下来的差值点,在这里做了一个线性插值算法来生成中间角度:float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); Camera 类是用来实现绕 Y 轴旋转后透视投影的,我们只需要其返回的 Matrix 值 , 这个值会赋给 Transformation 中的矩阵成员,当 ParentView 去为 ChildView 设置画布时,就会用它来设置坐标系,这样 ChildView 画出来的效果就是一个绕 Y 轴旋转同时带有透视投影的效果。利用这个动画便可以作出像立体翻页等比较酷的效果。

简单的使用

        Rotate3dAnimation rotate = new Rotate3dAnimation(0f, 180f, startAnim.getMeasuredWidth() / 2,startAnim.getMeasuredHeight() / 2, 0f, true);rotate.setFillAfter(true);rotate.setDuration(2000);startAnim.startAnimation(rotate);
startAnim这个View就能中心点绕着Z轴旋转了

触摸事件处理

触摸事件首先传递到ViewGroup中
ViewGroup的dispatchTouchEvent中有

    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,View child, int desiredPointerIdBits) {final boolean handled;……if (child == null) {handled = super.dispatchTouchEvent(transformedEvent);} else {final float offsetX = mScrollX - child.mLeft;final float offsetY = mScrollY - child.mTop;transformedEvent.offsetLocation(offsetX, offsetY);if (! child.hasIdentityMatrix()) {transformedEvent.transform(child.getInverseMatrix());}handled = child.dispatchTouchEvent(transformedEvent);}// Done.transformedEvent.recycle();return handled;}

   可以看到 offsetX,offsetY只对mScrollX,child.mLeft进行了取值。。。
    transformedEvent.transform(child.getInverseMatrix());不是前面设置的补间动画,而应该是属性动画。。
    如果设置的是属性动画,所以能在动画结束的位置获取到触摸事件,但是补间动画就不行了
。。

   public final Matrix getInverseMatrix() {ensureTransformationInfo();if (mTransformationInfo.mInverseMatrix == null) {mTransformationInfo.mInverseMatrix = new Matrix();}final Matrix matrix = mTransformationInfo.mInverseMatrix;mRenderNode.getInverseMatrix(matrix);return matrix;}
此时返回的Matrix对象跟mRenderNode对象有关联。而属性动画会改变属性,比如此时在一个view上设置一个TranslationX的属性动画,那么必然会调用
    该view的setTranslationX方法,果然此时操作了mRenderNode对象。。。setRotationX方法也一样
   public void setTranslationX(float translationX) {if (translationX != getTranslationX()) {invalidateViewProperty(true, false);mRenderNode.setTranslationX(translationX);invalidateViewProperty(false, true);invalidateParentIfNeededAndWasQuickRejected();notifySubtreeAccessibilityStateChangedIfNeeded();}}public void setRotationX(float rotationX) {if (rotationX != getRotationX()) {invalidateViewProperty(true, false);mRenderNode.setRotationX(rotationX);invalidateViewProperty(false, true);invalidateParentIfNeededAndWasQuickRejected();notifySubtreeAccessibilityStateChangedIfNeeded();}}

与Scroll的异同

前面有写过一篇《Android Scroll原理分析

1. 滑动之后还是可以处理触摸事件的,因为触摸事件处理mScrollX,mScrollY,可以在ViewGroup的dispatchTransformedTouchEvent方法中看到

2. 滑动的原理其实也是调整了该view画布canvas的坐标系,所以默认情况下,整个view都会滑动。比如viewgroup.scrollby(-10,10),那么viewgroup的viewgroup在dispatchDraw时绘制该viewgroup,就会把该viewgroup的画布translate10个单位,所以最终结果就是viewgroup在父控件中移动了10个单位一样,如果不是viewgroup,

view.scrollby(-10,10)也是一样。

3. 但是另外一种情况,比如系统自定义的view或者viewgroup,比如linearlayout布局,button,textview控件(可以看到textview中的onDraw方法应用了mScrollX,mScrollY。但为什么控件的位置不变呢? 很奇怪,不知道怎么做到的),滑动的是本身的内容,自身的位置却不变。这是怎么做到的,需要进一步研究,如果自定义view直接继承自view,或者直接继承子viewgroup,那么scrollto,scrollby移动的是整个控件

viewgroup.scrollby(-10,-10)。那么重绘的时候,会调用viewgroup的viewgroup的draw方法。。。

    public void scrollTo(int x, int y) {if (mScrollX != x || mScrollY != y) {int oldX = mScrollX;int oldY = mScrollY;mScrollX = x;mScrollY = y;invalidateParentCaches();onScrollChanged(mScrollX, mScrollY, oldX, oldY);if (!awakenScrollBars()) {postInvalidateOnAnimation();}}}
 invalidateParentCaches();
 postInvalidateOnAnimation();

有木有很熟悉,跟上面动画是基本差不多的,都是导致view的parent发生了重绘,进而导致了该view的重绘,但是不会引起viewgroup其它控件的重绘

      public void draw(Canvas canvas) {// Step 1, draw the background, if neededdrawBackground(canvas);// Step 3, draw the contentonDraw(canvas);            // Step 4, draw the childrendispatchDraw(canvas);// Step 6, draw decorations (foreground, scrollbars)onDrawForeground(canvas);}
   
dispatchDraw绘制顶层parent的子view,接着调用draw三个参数的重载方法。绘制该viewgroup

	boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {...........	int sx = 0;int sy = 0;if (!drawingWithRenderNode) {computeScroll();sx = mScrollX;sy = mScrollY;}final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;final boolean offsetForScroll = cache == null && !drawingWithRenderNode;int restoreTo = -1;if (!drawingWithRenderNode || transformToApply != null) {restoreTo = canvas.save();}if (offsetForScroll) {canvas.translate(mLeft - sx, mTop - sy);}...........	}

此时viewgroup的画布,被右下移动了10个单位。。所以最后viewgroup在parent中整个的被移动了10个单位。。。

  

    另一方面,mybutton是一个Button控件

    mybutton.scrollBy(-10, -10);
    那么最终的结果是button的内容右下平移了10个单位,而控件本身还停留在原来位置,这个比较费解,需要进一步研究。。

    linearlayout.scrollBy(-10, -10);

    最终结果linearlayout不变,里面的子控件全部右下移动10个单位,很奇怪。。。

  见如下:startscroll按钮分别对上下两个viewgroup进行scrollBy(-10, -10);

第一个viewgroup是我自定义的,直接继承子viewgroup,第二个viewgroup使用的系统自定义的linearlayout。。

那么最终结果,自定义的viewgroup,整个的右下移动了10个单位。linearlayout位置并没有移动,只是其中的子view发生了右下10个单位的移动

  


总结:

1. 相同点都是其实重绘了该view所在的viewgroup,进而重绘view本身,而不是直接重绘view本身(直接调用invalidate就是直接重绘view本身)。。。

2. 动画结束的地方是处理不了触摸事件,但是scrollto,scrollby结束的地方可以处理到。。。

动画总结

1. Animation中主要定义了动画的一些属性比如开始时间、持续时间、是否重复播放等,这个类主要有两个重要的函数:getTransformation 和 applyTransformation,
在 getTransformation 中 Animation 会根据动画的属性来产生一系列的差值点,然后将这些差值点传给 applyTransformation,
这个函数将根据这些点来生成不同的 Transformation,Transformation 中包含一个矩阵和 alpha 值,矩阵是用来做平移、旋转和缩放动画的
而 alpha 值是用来做 alpha 动画的(简单理解的话,alpha 动画相当于不断变换透明度或颜色来实现动画),以上面的平移矩阵为例子,
当调用 dispatchDraw 时会调用 getTransformation 来得到当前的 Transformation

2. Android动画就是通过ParentView来不断调整ChildView的画布canvas坐标系来实现的。发生动画的其实是ParentView而不是该view

3. 补间动画其实只是调整了子view画布canvas的坐标系,其实并没有修改任何属性,所以只能在原位置才能处理触摸事件。。。

参考:

1.Android 动画原理

2.Android动画原理分析


属性动画



http://chatgpt.dhexx.cn/article/3wP0IfFD.shtml

相关文章

补间动画和逐帧动画

补间动画 补间&#xff08;Tween&#xff09;动画通过对View进行一系列的图形变换来实现动画效果&#xff0c;其中图像变换包括平移、缩放、旋转、改变透明度等。补间动画最常用的方式是通过XML文件定义动画。 透明度渐变动画&#xff08;AlphaAnimation&#xff09; 主要通…

Android 动画—补间动画

帧动画是通过连续播放图片来模拟动画效果&#xff0c;而补间动画开发者只需指定动画开始&#xff0c;以及动画结束"关键帧"&#xff0c;而动画变化的"中间帧"则由系统计算并补齐&#xff01; 1.补间动画的分类和Interpolator Andoird所支持的补间动画效果…

【Android】补间动画用法最全详解

本文目录 补间动画概述和分类各类补间动画实现xml实现补间动画透明度动画-AlphaAnimation缩放动画-ScaleAnimation位移动画-TranslateAnimation旋转动画-RotateAnimation动画组合-AnimationSet 代码实现补间动画透明度动画&#xff08;AlphaAnimation&#xff09;缩放动画&…

补间动画详解一 基类Animation

补间动画(Tween animation)是通过在两个关键帧之间补充渐变的动画效果来实现的。 Android系统提供了四个补间动画的类,分别是AlphaAnimation、RotateAnimation、ScaleAnimation和TranslateAnimation,另外还有一个能够把多个动画组合起来的AnimationSet类,这些类都有一个共…

Android动画之补间动画

Android动画之补间动画 和上面一章学的帧动画不同&#xff0c;帧动画 是通过连续播放图片来模拟动画效果&#xff0c;而补间动画开发者只需指定动画开始&#xff0c;以及动画结束"关键帧"&#xff0c; 而动画变化的"中间帧"则由系统计算并补齐&#xff01…

使用Gstreamer处理RTSP视频流

文章目录 RTSP视频流处理方法1. Gstreamer整体框架1.1 Media Applications1.2 Core Framework1.3 Plugins 2. Gstreamer组件2.1 Element2.2 Pad2.3 Bin和Pipeline 3. gstreamer tools3.1 gst-inspect-1.03.2 gst-launch-1.0 4. 参考链接 RTSP视频流处理方法 这里使用Gstreamer…

GStreamer基础教程02——GStreamer概念

上一个教程演示了如何自动生成一个pipeline。这次我们打算用一个个element来手动搭建一个pipeline。我们这个教程会演示&#xff1a; 1. 什么是GStreamer的element以及如何建立一个element 2. 如何在element直接建立连接 3. 如何客制化element的行为 4. 如何监视总线上的错…

GStreamer功能详解

参考&#xff1a;https://blog.csdn.net/tx3344/article/details/7497434 参考&#xff1a;https://thebigdoc.readthedocs.io/en/latest/gstreamer/gst-concept.html 参考&#xff1a;https://blog.csdn.net/sdjhs/article/details/51444934 什么是GStreamer&#xff1f; …

基于gstreamer的rtsp推送和转发

基于gstreamer的rtsp推送和转发 一、配置gstreamer环境二、安装gstreamer-rtsp-server三、读取usb摄像头并推rtsp流四、转发rtsp 前段时间因为实验室项目要求&#xff0c;需要读取摄像头并推rtsp流&#xff0c;由于我们实验室不是做与之相关的工作&#xff0c;所以并没有什么参…

深入浅出gstreamer开发

Gstreamer解决什么问题&#xff1f; — 上层接口和应用方式的 相对稳定 与底层接口、平台环境的 多样化 。例如&#xff1a; codec 不同种类不同实现&#xff0c;音视频处理不同&#xff0c;硬件输入、输出、采集播放不同&#xff0c;芯片不同&#xff0c;操作系统不同。 — 通…

【GStreamer 】3-1 gstreamer插件之 videotestsrc 介绍

目录 ​编辑 1、简介 2、videotestsrc 3、videotestsrc 不同pattern参数测试罗列 3.1 (0): smpte - SMPTE 100% color bars 3.2 (1): snow - Random (television snow) 3.3 (2): black - 100% Black ​编辑 3.4 checkers 方块 ​编辑 3.5 几何图形 4、videotestsrc…

Gstreamer概述

1、什么是GStreamer GStreamer 是用来构建流媒体应用的开源多媒体框架(framework)&#xff0c;其基本设计思想来自于俄勒冈(Oregon)研究生学院有关视频管道的创意, 同时也借鉴了DirectShow的设计思想。其目标是要简化音/视频应用程序的开发&#xff0c;已经能够被用来处理像 M…

gstreamer简介

常用 gchar * caps_string gst_caps_to_string (new_selected_caps); g_free (caps_string); 需要弄懂的问题 tunnel tee queue 最后列一下Gstreamer中常见的时间宏&#xff0c;注意Gstreamer中的时间单位是&#xff1a;纳秒 #define G_USEC_PER_SEC 1000000 #define GST_S…

Gstreamer基础知识介绍

由于deepstream是基于gstreamer的&#xff0c;所以要想在deepstream上做拓展&#xff0c;需要对gstreamer有一定的认识。以下主要介绍Gstreamer整体框架和Gstreamer基础概念。 一、Gstreamer整体框架 gstreamer是一个用于开发流式多媒体应用的开源框架。本身这个框架是为了更…

【GStreamer 】1-扫盲介绍

从历史的角度来看&#xff0c;Linux 在多媒体方面已经远远落后于其它的操作系统。微软的Windows和苹果的MacOS它们对多媒体设备、多媒体创作、播放和实时处理等方面已经有了很好的支持。另一方面&#xff0c;Linux对多媒体应用的综合贡献比较少&#xff0c;这也使得Linux很难在…

详细的GStreamer开发教程

详细的GStreamer开发教程 文章目录 详细的GStreamer开发教程1. 什么是GStreamer&#xff1f;2. GStreamer架构2.1 Media Applications2.2 Core Framework2.3 Plugins 3. GStreamer组件3.1 Element创建一个 GstElement 3.2 箱柜&#xff08;bin&#xff09;元件的状态 3.3 衬垫&…

gstreamer(一)入门和概述

一&#xff0e;概述 在音视频领域接触最多实现的方案通常是通过ffmpeg&#xff08;PC和sever端居多&#xff09;或者硬件厂家的的SDK实现特定硬件的编解码功能&#xff08;机顶盒&#xff0c;电视等嵌入式设备&#xff09;。这里我们介绍一个在国内不太常用的解决方案----gstr…

二、什么是GStreamer

GStreamer是一个用于创建流媒体应用程序的框架。基本的设计来自俄勒冈研究生院的视频管道&#xff0c;还有一些来自DirectShow的想法。 GStreamer的开发框架使编写任何类型的流媒体应用程序成为可能。GStreamer框架旨在使编写处理音频或视频或两者同时处理的应用程序变得容易。…

Gstreamer 应用开发:1-基础介绍

我们之前的系列&#xff0c;正式的介绍了Gstreamer&#xff0c;并且围绕如何使用USB相机推流实现RTSP服务器来做了介绍&#xff0c;并在Jeston TX1 平台上做了优化急速的一些探索。 今天我们开始围绕如何用命令实现一个音视频混合&#xff0c;或者单独的音频&#xff0c;和单独…

【gstreamer】入门介绍

概述 GStreamer是一个基于流媒体的框架&#xff0c;是一个开放源代码的多媒体框架&#xff0c;用于创建音频和视频处理应用程序。它是一个运行在多个操作系统上的跨平台框架&#xff0c;支持多种不同的多媒体格式。 GStreamer框架的核心是基于插件的体系结构&#xff0c;插件…