FFMPEG 之视频播放

2023-05-16

先看界面效果,虽然有点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="";

    @Override
    protected 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() {
            @Override
            public 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、一帧一帧读取压缩的视频数据AVPacket
    int len, got_frame, framecount = 0;
    while (av_read_frame(pFormatCtx, packet) >= 0) {
        //AVPacket
        len = 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_8888
            I420ToARGB(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


            //unlock
            ANativeWindow_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-lib
             SHARED
             src/main/cpp/native-lib.c )
find_library(log-lib
              log )


add_library(libavcodec-56
            SHARED
            IMPORTED)

set_target_properties(libavcodec-56
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavcodec-56.so)

add_library(libavdevice-56
            SHARED
            IMPORTED)
set_target_properties(libavdevice-56
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavdevice-56.so)

add_library(libavfilter-5
            SHARED
            IMPORTED)
set_target_properties(libavfilter-5
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavfilter-5.so)

add_library(libavformat-56
            SHARED
            IMPORTED)
set_target_properties(libavformat-56
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavformat-56.so)
add_library(libavutil-54
            SHARED
            IMPORTED)
set_target_properties(libavutil-54
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libavutil-54.so)
add_library(libpostproc-53
            SHARED
            IMPORTED)
set_target_properties(libpostproc-53
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libpostproc-53.so)

add_library(libswresample-1
            SHARED
            IMPORTED)
set_target_properties(libswresample-1
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libswresample-1.so)
add_library(libswscale-3
           SHARED
           IMPORTED)
set_target_properties(libswscale-3
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libswscale-3.so)

add_library(libyuv
            SHARED
            IMPORTED)
set_target_properties(libyuv
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libyuv.so)

target_link_libraries(  native-lib
                        android
                        libavcodec-56
                        libavdevice-56
                        libavfilter-5
                        libavformat-56
                        libavutil-54
                        libpostproc-53
                        libswresample-1
                        libswscale-3
                        libyuv
                       ${log-lib} )
10、build文件加入对应的cmake编译资源


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

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





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FFMPEG 之视频播放 的相关文章

  • 为什么处理时间随着修剪位置的增加而增加?

    我最近一直在使用ffmpeg修剪一些视频 我注意到随着修剪位置的增加 修剪视频所花费的时间也会增加 即使持续时间相同 5 seconds 下面给出了修剪视频的命令0 to 5秒 处理仅需1秒 ffmpeg y i input mp4 fil
  • 致命错误:libavcodec/avcodec.h 没有这样的文件或目录编译终止

    我正在尝试使用 gcc 执行tutorial01 c 并且 gcc 和tutorial01 c 以及 libavcodec 和 libavformat 及其关联文件位于同一文件夹中 它给了我这个错误 致命错误 libavcodec avco
  • 如何启用 FFMPEG 日志记录?

    我想调试 ffmpeg 我添加以下代码来打印日志 av log s AV LOG PANIC fmt or printf msg 但这行不通 没有任何调试信息 然后我启用调试构建选项 export COMMON FF CFG FLAGS C
  • FFMPEG:将 YUV 数据转储到 AVFrame 结构中

    我正在尝试转储YUV420数据进入AVFrameFFMPEG 的结构 从下面的链接 http ffmpeg org doxygen trunk structAVFrame html http ffmpeg org doxygen trunk
  • id3 图像编辑后播放 mp3 时遇到问题

    由于硬件限制 我们生产的软件试图确保导入到其库中的任何音频文件 准备复制到硬件上 都是可接受的比特率 最近 我们开始使用 FFmpeg 将许多不同的音频类型转换为 mp3 以便在我们的硬件上导入和使用它们 虽然转换工作正常并且 mp3 文件
  • FFmpeg 缩放不是平滑中心(而是锯齿形)

    我尝试执行基本操作zoompan https www ffmpeg org ffmpeg all html zoompan with FFmpeg 我有一个输入图像 png 1280x720 并从中创建一个 8 秒的视频 mp4 320x1
  • 如何从 ffmpeg 中打开的文件获取流信息?

    我正在尝试使用 ffmpeg 读取视频文件 我有与其旧版本相对应的工作代码 并开始尝试升级到最新的构建版本 将所有这些已弃用的函数替换为其实际的类似函数 但是我遇到了问题 似乎没有检索到任何流 并且视频负载停止在轨道中 这是我正在使用的代码
  • PowerShell 脚本 ffmpeg

    作为一名优秀的 Windows 系统管理员 我终于开始学习 PowerShell 话虽这么说 我不知道我在做什么 惊讶 惊讶 我认为远离生产环境 在家里使用 PowerShell 对我来说将是一次很好的学习经历 最近 我开始使用 FFMPE
  • 使用 ffmpeg 将 mp4 转换为 gif 时帧率较低

    我正在使用 ffmpeg 将高质量视频转换为 gif 大多数视频都是 60fps 及以上720p 但是当我使用下面的代码将视频转换为 gif 时 我得到的 gif 输出的 fps 非常低 usr bin env palette tmp pa
  • 将循环视频添加到声音 ffmpeg

    我开始使用 ffmpeg 这是我的第一个疑问 我有一个声音文件 example mp3 持续时间 1 分钟 我想添加一个循环视频 example mp4 x 秒持续时间 在这种情况下 我想生成 1 分钟的 mp4 视频并循环该视频 3 次
  • 如何在不指定像素格式的情况下从 AVFrame.data[] 和 AVFrame.linesize[] 获取原始帧数据?

    我的总体想法是frame data 根据视频的像素格式 RGB 或 YUV 进行解释 但是有没有通用的方法可以从帧中获取所有像素数据 我只想计算帧数据的哈希值 而不解释它来显示图像 根据 AVFrame h uint8 t AVFrame
  • 使用 mp4box 直播破折号内容

    我正在尝试直播H 264内容到HTML5使用媒体源扩展 API 下面的方法效果很好 ffmpeg i rtsp 10 50 1 29 media video1 vcodec copy f mp4 reset timestamps 1 mov
  • FFMPEG:尝试从图像和音频创建 facebook 流时出现转换失败错误?

    目标是从图像和音频文件创建 Facebook 流 这是我的命令 ffmpeg re y loop 1 f image2 i maxresdefault jpg i audio loop mp3 ar 44100 b a 128k vcode
  • 将yuv420p原始数据转换为opencv图像

    我有来自 rtmp 服务器的原始数据 像素格式为 yuv420p 我使用管道来读取数据 但我不知道如何将原始数据解码为图像 command ffmpeg command extend loglevel fatal i rtmp localh
  • FFmpeg 代码无法在用于缩略图提取的 http url 上工作

    我正在尝试从 sharepoint 2013 视频库中提取缩略图 我找到了一个可以使用 ffmpeg 提取的链接 这是链接 如何将视频的第一帧保存为图像 https stackoverflow com questions 3575311 h
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • 未找到 ffmpeg 命令,但 pip 列表显示 ffmpeg

    我一直在尝试使用命令安装 ffmpegpip install ffmpeg我正在没有 sudo 权限的服务器上执行此操作 在编写 ffmpeg 时 我得到 ffmpeg command not found 然后我检查了pip list它显示
  • 从视频中删除所有非关键帧,无需重新编码

    我有一个 HEVC mkv 视频 我需要从中删除除关键帧之外的所有内容 而无需重新编码整个内容 我发现我可以使用这个额外的关键帧 ffmpeg i full mkv c v copy vf select eq pict type PICT
  • Mac 上的 FFMPEG 和 PHP 不起作用

    我需要你的帮助 目前我使用 Mac OS X 10 9 4 和 xampp apache 1 8 3 3 我需要使用ffmpeg 版本3 2 通过php转换视频文件exec 但我无法让它发挥作用 我做了一些运行终端命令行的测试 系统运行正常
  • 使用 ffmpeg 在一个音频文件中实现多个淡入/淡出效果

    我在向一个音频文件添加多种淡入淡出效果时遇到一些问题 当我尝试使用这样的命令时 ffmpeg y i home user video test sound mp3 af afade t in ss 0 d 3 afade t out st

随机推荐

  • 本地显示远程服务器图形界面

    解决方案 序号方案简单区别方案一Xmanager1 VNC连接时及时突然中断 xff08 比如断网 xff09 xff0c 不影响操作进行 xff1b 2 不需要在服务器上装软件 xff0c 需要在你的电脑上装相应软件 xff0c 使用SS
  • SQL解析json(包含单层解析、多层解析)解析的数据可直接存到表中

    单层json解析 声明变量 declare 64 JsonData nvarchar max 61 39 34 BillName 34 34 12345765 34 34 SendDate 34 34 2022 11 10T00 00 00
  • MySQL查看当前使用的配置文件my.cnf的方法

    MySQL查看当前使用的配置文件my cnf的方法 MySQL实例在启动时 xff0c 会先读取配置参数文件my cnf my cnf一般会放在MySQL的安装目录中 xff0c 用户也可以放在其他目录加载 安装MySQL后 xff0c 系
  • Latex 之 微分符号d的竖立表达 {\rm d}

    微分符号d竖立表达 rm d
  • Abaqus 导出XYdata的几种方式

    目录 方法一 xff1a 通过Plu ins gt Tools gt Excel Utilities xff0c 将XY Data直接到Excel文件里 xff01 方式二 xff1a Report gt XY xff0c 导出默认 rpt
  • ABAQUS 显示应力/应变场的最大/最小值

    如下图所示 xff0c 可以显示最大最小值 具体数据导出 xff1a Report gt Field Output 导出结果 场输出 xff08 Field output xff09 同一时刻 xff0c 不同位置 xff1b 历史输出 H
  • mac下重装系统,应用程序副本已损坏 的解决办法

    首先需要确定电脑的年份和对应的系统 xff0c 简单的道理是老的电脑硬件是不适配最新系统的 xff0c 我需要安装的是10 12的系统 系统来源 xff1a 黑苹果 年份确定 xff1a 2017年9月之前生产的电脑 我用的是U盘安装的方法
  • mysql查看数据库的容量及表容量

    select table schema sum DATA LENGTH 43 sum INDEX LENGTH from information schema tables group by table schema 在需要备份数据库里面的
  • 【数据结构-栈】借助栈实现回文的判断

    数据结构 栈 借助栈实现回文的判断 最近在学习栈 xff0c 尝试用C实现了一些功能 include lt stdio h gt include lt stdlib h gt typedef struct app char date str
  • C语言实现冒泡排序

    冒泡排序作为学习排序最基本的算法 xff0c 具有稳定性与实用性 下面是C语言冒泡排序的源代码 include lt stdio h gt int main void int a 10 61 6 4 3 2 7 8 9 10 1 5 int
  • C语言实现快速排序算法

    快排作为公认最优秀的排序方法 xff0c 是每一个程序员都应该掌握的 xff0c 那么 xff0c 今天就由我来为大家简单讲解一下快速排序算法的代码 源代码如下 xff1a include lt stdio h gt void quicks
  • C语言实现二分查找

    相较于线性查找 xff0c 二分查找在面对大量数据时的效率更高 xff0c 但它的缺点是只能对有序数组进行查找 源代码如下 xff1a include lt stdio h gt void binarysearch int a int su
  • 约瑟夫环详解

    package newjosephu public class myfinaljosephu 你可能会说crazy 我只想说ez xff01 public static void main String args circlelinkedl
  • ECS弹性云服务器常用端口、安全组

    弹性云服务器常用端口 弹性云服务器常用端口如 表1 所示 您可以通过配置安全组规则放通弹性云服务器对应的端口 xff0c 详情请参见 添加安全组规则 表1 弹性云服务器常用端口 协议 端口 说明 FTP 21 FTP服务上传和下载文件 SS
  • 01背包问题(滚动数组实现的逻辑)

    package tttest public class mybetterbag public static void main String args int weight 61 1 3 4 int bagsize 61 4 int val
  • java递归实现辗转相除法

    public static int getres int a int b if b 61 0 return getres b a b return a
  • java 线索二叉树的构建

    public class test public static void main String args Node root 61 new Node 1 Node node2 61 new Node 2 Node node3 61 new
  • ubuntu下查看文件(夹)大小的命令

    记录下自己常用的查看文件夹和文件大小的命令 查看当前所处的文件夹的整个大小 xff08 不包括具体内容 xff0c 只看当前文件夹大小 xff09 span class token function du span sh 查看当前文件夹中各
  • git stash时出现xxx:needs merge问题

    项目需要git merge其他分支 xff0c 但由于本地也修改过 xff0c 所以希望先git stash后再merge xff0c 这时出现以下问题 xff1a xxx xxx xxx cpp xff1a needs merge 通过g
  • FFMPEG 之视频播放

    先看界面效果 xff0c 虽然有点low xff0c 但是效果实现了 一 实现原理 1 使用ffmpeg解码视频 2 然后使用libyuv播放解码的视频 二 实现 1 先看目录结构 2 ffmpeg编译以及引用 xff0c 在之前的篇章已经