先看界面效果,虽然有点low,但是效果实现了

一、实现原理

1、使用ffmpeg解码视频

2、然后使用libyuv播放解码的视频

二、实现

1、先看目录结构

2、ffmpeg编译以及引用,在之前的篇章已经说过了,不知道得可以看看之前的文章

3、编译libyuv

1、首先在https://chromium.googlesource.com/external/libyuv下载源码,然后上传至Linux服务器下(因为我是在Linux下编译的)

2、这是libyuv的目录

3、创建libyuv目录,在下边创建jni目录,把libyuv源码拷入jni目录下

4、编译libyuv,进入jni目录下输入ndk-build命令,编译即可,然后会生成相应的so和头文件

这是生成好的目录,在libs中就有生成好的so文件

5、把生成好的so放入对应的文件,把源码中include文件的源码放入Android项目中

4、创建native方法PlayerControl.java

package com.xiaofan.testffmpeg2;import android.view.Surface;public class PlayerControl {public native void render(String input, Surface surface);static {System.loadLibrary("avutil-54");System.loadLibrary("swresample-1");System.loadLibrary("avcodec-56");System.loadLibrary("avformat-56");System.loadLibrary("swscale-3");System.loadLibrary("postproc-53");System.loadLibrary("avfilter-5");System.loadLibrary("avdevice-56");System.loadLibrary("native-lib");}
}

5、使用javah命令生成头文件

com_xiaofan_testffmpeg2_PlayerControl.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_xiaofan_testffmpeg2_PlayerControl */#ifndef _Included_com_xiaofan_testffmpeg2_PlayerControl
#define _Included_com_xiaofan_testffmpeg2_PlayerControl
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_xiaofan_testffmpeg2_PlayerControl* Method:    render* Signature: (Ljava/lang/String;)V*/
JNIEXPORT void JNICALL Java_com_xiaofan_testffmpeg2_PlayerControl_render(JNIEnv *, jobject, jstring, jobject);
#ifdef __cplusplus
}
#endif
#endif

6、创建自定义SurfaceView控件,

VideoView.java

package com.xiaofan.testffmpeg2.customview;
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class VideoView extends SurfaceView{public VideoView(Context context) {super(context);init();}public VideoView(Context context, AttributeSet attrs) {super(context, attrs);init();}public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init(){//初始化,SurfaceView绘制的像素格式SurfaceHolder holder=getHolder();//RGBA_8888 色彩丰富,但是占用的内存大holder.setFormat(PixelFormat.RGBA_8888);}
}

7、在Activity中调用播放方法

MainActivity.java

package com.xiaofan.testffmpeg2;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.xiaofan.testffmpeg2.customview.VideoView;
import java.io.File;
public class MainActivity extends AppCompatActivity {VideoView myVideoView;private PlayerControl playerControl;private String inputStr="";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);playerControl=new PlayerControl();myVideoView = findViewById(R.id.myVideoView);inputStr= new File(Environment.getExternalStorageDirectory(), "aaaa.mp4").getAbsolutePath();findViewById(R.id.test).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {playerControl.render(inputStr,myVideoView.getHolder().getSurface());}});}}

8、编译解码文件

native-lib.c

#include "com_xiaofan_testffmpeg2_PlayerControl.h"
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>#define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"wanxiaofan",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"wanxiaofan",FORMAT,##__VA_ARGS__);
//封装格式
#include "include/ffmpeg/libavformat/avformat.h"
//解码
#include "include/ffmpeg/libavcodec/avcodec.h"
//缩放
#include "include/ffmpeg/libswscale/swscale.h"
#include "include/ffmpeg/libavutil/avutil.h"
#include "include/ffmpeg/libavutil/frame.h"#include "include/libyuv/libyuv.h"
#include <unistd.h>JNIEXPORT void JNICALL Java_com_xiaofan_testffmpeg2_PlayerControl_render(JNIEnv *env, jobject obj, jstring input_jstr, jobject surface) {const char *input_cstr = (*env)->GetStringUTFChars(env, input_jstr,JNI_FALSE);//1、注册组件av_register_all();//2、打开输入视频文件AVFormatContext *pFormatCtx = avformat_alloc_context();LOGE("%s", input_cstr);if (avformat_open_input(&pFormatCtx, input_cstr, NULL, NULL) != 0) {LOGE("%s", "打开输入视频文件失败!");return;};//3、获取视频信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {LOGE("%s", "获取视频信息失败!");return;}//视频解码,需要找到视频对应的AVStream所在pFormatCtx->streams的索引位置int video_stream_idx = -1;int i = 0;for (; i < pFormatCtx->nb_streams; i++) {if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_idx = i;break;}}//4.获取视频解码器AVCodecContext *pCodeCtx =pFormatCtx->streams[video_stream_idx]->codec;AVCodec *pCodec = avcodec_find_decoder(pCodeCtx->codec_id);if (pCodec == NULL) {LOGE("%s", "无法解码!");return;}//5、打开解码器if (avcodec_open2(pCodeCtx, pCodec, NULL) < 0) {LOGE("%s", "无法打开解码器!");return;};//压缩数据AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));//像素数据(解码数据)AVFrame *yuvFrame = av_frame_alloc();AVFrame *rgbFrame = av_frame_alloc();//native绘制ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);//只有指定了AVFrame的像素格式、画面大小才能真正分配内存//缓冲区分配内存uint8_t *out_buffer = (uint8_t *) av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodeCtx->width, pCodeCtx->height));//初始化缓冲区avpicture_fill((AVPicture *) yuvFrame, out_buffer, AV_PIX_FMT_YUV420P,pCodeCtx->width, pCodeCtx->height);ANativeWindow_Buffer outBuffer;//6、一帧一帧读取压缩的视频数据AVPacketint len, got_frame, framecount = 0;while (av_read_frame(pFormatCtx, packet) >= 0) {//AVPacketlen = avcodec_decode_video2(pCodeCtx, yuvFrame, &got_frame, packet);//非零,正在解码if (got_frame) {LOGI("解码%d帧", framecount++);//lock//设置缓冲区的宽、高、像素格式ANativeWindow_setBuffersGeometry(nativeWindow, pCodeCtx->width, pCodeCtx->height,WINDOW_FORMAT_RGBA_8888);ANativeWindow_lock(nativeWindow, &outBuffer, NULL);//设置yuvFrame的缓冲区,像素格式//rgb_fragme缓冲区与outBuffer.bits是同一块内存avpicture_fill((AVPicture *) rgbFrame, outBuffer.bits, PIX_FMT_RGBA, pCodeCtx->width,pCodeCtx->height);//YUV->RGBA_8888I420ToARGB(yuvFrame->data[0], yuvFrame->linesize[0],yuvFrame->data[2], yuvFrame->linesize[2],yuvFrame->data[1], yuvFrame->linesize[1],rgbFrame->data[0], rgbFrame->linesize[0],pCodeCtx->width, pCodeCtx->height);//fix buffer//unlockANativeWindow_unlockAndPost(nativeWindow);usleep(1000 * 16);}av_free_packet(packet);}ANativeWindow_release(nativeWindow);avcodec_close(pCodeCtx);avformat_free_context(pFormatCtx);(*env)->ReleaseStringUTFChars(env, input_jstr, input_cstr);
}

9、CMakeLists.txt


cmake_minimum_required(VERSION 3.4.1)add_library(native-libSHAREDsrc/main/cpp/native-lib.c )
find_library(log-liblog )add_library(libavcodec-56SHAREDIMPORTED)set_target_properties(libavcodec-56PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavcodec-56.so)add_library(libavdevice-56SHAREDIMPORTED)
set_target_properties(libavdevice-56PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavdevice-56.so)add_library(libavfilter-5SHAREDIMPORTED)
set_target_properties(libavfilter-5PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavfilter-5.so)add_library(libavformat-56SHAREDIMPORTED)
set_target_properties(libavformat-56PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavformat-56.so)
add_library(libavutil-54SHAREDIMPORTED)
set_target_properties(libavutil-54PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavutil-54.so)
add_library(libpostproc-53SHAREDIMPORTED)
set_target_properties(libpostproc-53PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libpostproc-53.so)add_library(libswresample-1SHAREDIMPORTED)
set_target_properties(libswresample-1PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libswresample-1.so)
add_library(libswscale-3SHAREDIMPORTED)
set_target_properties(libswscale-3PROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libswscale-3.so)add_library(libyuvSHAREDIMPORTED)
set_target_properties(libyuvPROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libyuv.so)target_link_libraries(  native-libandroidlibavcodec-56libavdevice-56libavfilter-5libavformat-56libavutil-54libpostproc-53libswresample-1libswscale-3libyuv${log-lib} )

10、build文件加入对应的cmake编译资源

这样就可以播放视频了,支持的格式还挺多,比如mp4、mkv、avi、flv等格式都支持

我会在我的资源里边附上libyuv的源码和编译好的so文件

FFMPEG 之视频播放相关推荐

  1. 从零开始学习音视频编程技术(七) FFMPEG Qt视频播放器之SDL的使用

    从零开始学习音视频编程技术(七) FFMPEG Qt视频播放器之SDL的使用 原文地址:http://blog.yundiantech.com/?log=blog&id=10 前面介绍了使用F ...

  2. 从零开始学习音视频编程技术(六) FFMPEG Qt视频播放器之显示图像

    从零开始学习音视频编程技术(六) FFMPEG Qt视频播放器之显示图像 原文地址:http://blog.yundiantech.com/?log=blog&id=9 前面讲解了如何用FFM ...

  3. 基于FFmpeg的视频播放器之十一:倍速播放

    倍速播放通常有两种方式:一种是变速变调,另一种是变速不变调 一.变速变调 这种方法的原理就是音频重采样.比如说44100Hz采样率的音频,每秒钟有44100个采样点,如果我们要加速为200%播放,最简 ...

  4. FFmpeg+SDL视频播放器

    本博客是摘自雷霄骅大神的课程<基于 FFmpeg + SDL 的视频播放器的制作>课程 里的内容,非常适合音视频小白入门,在这里感谢雷神的指导! 目录 FFmpeg和SDL的整合实现视频播 ...

  5. QT软件开发-基于FFMPEG设计视频播放器-解码音频(三)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于 ...

  6. QT软件开发-基于FFMPEG设计视频播放器-软解图像(一)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于 ...

  7. 基于FFmpeg的视频播放器之十五:录像

    一.效果 1.录制视频 2.播放录制的视频 二.原理 将上一篇基于FFmpeg的视频播放器之十四:remuxing中的代码直接用于录像是行不通的,会存在下列问题. 1.因为可以从任意时间点开始录制,此 ...

  8. QT软件开发-基于FFMPEG设计视频播放器-GPU硬解、OpenGL渲染、解码音频完整例子(六)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于 ...

  9. QT软件开发-基于FFMPEG设计视频播放器-GPU硬解、OpenGL渲染(四)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于 ...

  10. 基于FFmpeg开发视频播放器, 基本流程(一)

    刚开始学习FFmpeg,用几篇文章记录下,使用ffmpeg开发一个简单的视频播放器,大概的过程.这里只讨论核心代码,如解封装,音频的解码播放,视频的解码播放,音视频同步,不涉及UI布局. 基于FFmp ...

最新文章

  1. SharePoint 2013中的视频体验增强(1)——把大象装进冰箱
  2. android 耳机检测,android – 检测耳机是否有麦克风
  3. 优秀的java代码_像这样写,Java菜鸟也能写出牛逼的代码
  4. 【Vegas原创】分别用Toad、EM解表锁
  5. 哇、、、、C++ 实现单向链表
  6. Chrome浏览器插件Tab Groups Extension使用方法
  7. 贪心算法之取手套问题(牛客)
  8. 1 MySQL的备份和还原常见命令
  9. 如何给一个文件重命名?
  10. 以太坊地址和公钥_以太坊的私钥、公钥、地址、账户
  11. 计算机网络技术云计算简历模板,云计算平台师个人简历模板
  12. 如何快速从入门到精通linux
  13. 继承 方法重写 组合(尚学堂视频学习总结_003)
  14. 用java语言编写选课系统_求用JAVA为我写一个简单的选课系统程序,实现增,删,改,查功能...
  15. 认识 DELL EMC VPLEX VS6物理配置
  16. windows系统文件名不能包含哪些字符
  17. Qt win7中读取Excel会出现闪退的问题
  18. php div 居中代码,Div水平居中效果怎么实现
  19. 零基础大龄人士的Python学习记录(1)
  20. IE8有淘宝定制版,火狐也出了个淘宝专版浏览器。喜欢火狐的试试吧。

热门文章

  1. 读书笔记—交互设计-简约至上
  2. 计算机科学与技术用惠普星15,惠普星15和14性能对比
  3. macbook文件恢复|如何找回Mac废纸篓已删除的文件?
  4. java 怎么产生随机数_Java怎么产生随机数
  5. 贵阳大数据发展方向是什么?大数据相关岗位是什么?
  6. 2020全网最全的软件测试linux面试题及参考答案,赶紧收藏!
  7. git小乌龟轻松解决代码冲突
  8. oracle数据库的相关认证,全新Oracle数据库认证认证指南
  9. R的32位与64位的区别!
  10. 如何为Schlage Connect Smart Lock创建和管理用户代码