Android_音视频开发进阶使用FFmpeg播放视频!音视频转换器

抖店动销抖店体验分提升抖店任何业务可添加微信:ad07668

1.FFmpeg简单的说明多媒体视频处理工具FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。他的功能有7大部分完整libavcodec:提供范围更广的编解码器的实现。libavformat:实现流媒体协议,容器格式和基本的I/O访问。li

1.FFmpeg简单的说明

多媒体视频处理工具FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。

他的功能有7大部分完整

libavcodec:提供范围更广的编解码器的实现。

libavformat:实现流媒体协议,容器格式和基本的I/O访问。

libavutil:包括校验,解压缩和各种实用功能。

libavfilter:提供了一个平均改变解码音频和视频通过过滤器链。

libavdevice:提供抽象访问捕获和重放设备。

libswresample:实现音频混合和重采样程序。

libswscale:实现颜色转换和缩放程序。

2.环境配置

将下载的项目里jniLibs和cpp粘贴到自己创建的项目的main文件夹下

我还需要在app module的build.gradle添加代码,在defaultConfig里添加ndk支持的类型,还有给Cmake添加参数,在android下导入CMakeLists文件,例子代码如下:

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "jonesx.videoplayer"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk {
            abiFilters 'armeabi'
        }
        externalNativeBuild {
            cmake {
                arguments '-DANDROID_TOOLCHAIN=clang','-DANDROID_STL=gnustl_static'
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

【相关学习资料推荐,点击下方链接免费报名,先码住不迷路~】

【免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发-学习视频教程-腾讯课堂

C++音视频配套学习资料点击莬费领取「链接」

3.代码说明

首先就是能够使用cpp文件夹下的VideoPlayer的代码,那我们就需要创建一个VideoPlayer的java

public class VideoPlayer {
 
    static {
        System.loadLibrary("VideoPlayer");
    }
 
    public static native int play(Object surface);
}

使用这个play函数,直接在SurfaceView的surfaceCreated函数里开启线程使用

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                VideoPlayer.play(surfaceHolder.getSurface());
            }
        }).start();
    }

那重点来了,说一说VideoPlayer用到了FFmpeg哪些东西

获取视频格式的环境,打开MP4文件

AVFormatContext *pFormatCtx = avformat_alloc_context();
 
    if (avformat_open_input(&pFormatCtx, file_name, NULL, NULL) != 0) {
 
        LOGD("Couldn't open file:%s\n", file_name);
        return -1; // Couldn't open file
    }

查看是否有流,如果那就看是否有视频流

    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        LOGD("Couldn't find stream information.");
        return -1;
    }
 
    int videoStream = -1, i;
    for (i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO
            && videoStream < 0) {
            videoStream = i;
        }
    }
    if (videoStream == -1) {
        LOGD("Didn't find a video stream.");
        return -1; // Didn't find a video stream
    }

获得视频解码器环境,然后看这个解码器是否能够开启

    AVCodecContext *pCodecCtx = pFormatCtx->streams[videoStream]->codec;
 
    // Find the decoder for the video stream
    AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if (pCodec == NULL) {
        LOGD("Codec not found.");
        return -1; // Codec not found
    }
 
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        LOGD("Could not open codec.");
        return -1; // Could not open codec
    }

通过surface获取目前手机屏幕给这个Surface的内存空间

    // 获取native WINDOW
    ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
 
    // 获取视频宽高
    int videoWidth = pCodecCtx->width;
    int videoHeight = pCodecCtx->height;
 
    // 设置native window的buffer大小,可自动拉伸
    ANativeWindow_setBuffersGeometry(nativeWindow, videoWidth, videoHeight,
                                     WINDOW_FORMAT_RGBA_8888);
    ANativeWindow_Buffer windowBuffer;
 
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        LOGD("Could not open codec.");
        return -1; // Could not open codec
    }

转格式

   struct SwsContext *sws_ctx = sws_getContext(pCodecCtx->width,
                                                pCodecCtx->height,
                                                pCodecCtx->pix_fmt,
                                                pCodecCtx->width,
                                                pCodecCtx->height,
                                                AV_PIX_FMT_RGBA,
                                                SWS_BILINEAR,
                                                NULL,
                                                NULL,
                                                NULL);

首先这个解码是在一个循环里,然后解码,和之前一样一帧一帧的解码,但是如果一帧太大那就下一次循环里继续解码

avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

释放资源

    av_free(buffer);
    av_free(pFrameRGBA);
 
    // Free the YUV frame
    av_free(pFrame);
 
    // Close the codecs
    avcodec_close(pCodecCtx);
 
    // Close the video file
    avformat_close_input(&pFormatCtx);

如果你对音视频开发感兴趣,或者对本文的一些阐述有自己的看法,可以在下方的留言框,一起探讨。

抖店动销抖店体验分提升抖店任何业务可添加微信:ad07668

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 sumchina520@foxmail.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.zg8899.cn/23666.html