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

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

基于FFmpeg开发视频播放器, 基本流程(一)  https://blog.csdn.net/lin20044140410/article/details/104847588

基于FFmpeg开发视频播放器,视频解码播放(二) https://blog.csdn.net/lin20044140410/article/details/104849552

基于FFmpeg开发视频播放器,音频解码播放(三) https://blog.csdn.net/lin20044140410/article/details/104851476

基于FFmpeg开发视频播放器,音视频同步(四)  https://blog.csdn.net/lin20044140410/article/details/104857038

http://ffmpeg.org/

一, FFmpeg是一套用来记录,转换数字音频,视频,并能将其转化为流的开源项目,拥有丰富的命令来实现音视频相关的操作,其源码是以模块化的方式进行构建,可以根据需要选择不同模块进行集成使用.

FFmpeg还可以集成第三方的库,用ffmpeg的统一接口来使用,比如常用的librtmp,libMP3lame等.

FFmpeg主要有以下几个模块:

libavformat  用于各种音视频封装格式的生成和解析

libacodec  用于声音,图像的编解码

libavfilter 用于音视频滤波器的开发.

libavutil   提供一些公共的工具函数

libswresample 用于音频格式的转码,如转成PCM流

libswscale 用于图像格式的转换,缩放,如RGB 和YUV的转换

libpostproc 用于后期效果的处理.

二, 播放器开发中涉及到的一些概念

原始数据 :能够表示完整的图像,声音的数据格式,如RGB,PCM.

编码格式:存储编码后数据的容器,如MP4,FLV等,

AVPacket  解码前的数据结构体.

AVFrame   解码后的数据结构体.

AVFormatContext  媒体文件的构成和基本信息上下文.

AVCodecContext   解码信息上下文.

三,播放器的开发流程,借用一张网上的图片:

四, 准备环境,

 对音视频的处理都是在native层,所以要新建一个Native项目,当然也可以新建Android项目,然后手动添加CPP模块,

前提是要先编译好ffmpeg相关的库,静态库,动态库都行,这里用的时静态库,这个库要依据你手机CPU的架构来导入.

gradle的配置没有特别注意的地方,如果你是Android项目,要注意在build.gradle中配置:

    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }

CMakeLists.txt的配置,主要时设置源文件路径,引入头文件,链接依赖库,

cmake_minimum_required(VERSION 3.4.1)


aux_source_directory(. SOURCE)
add_library( # Sets the name of the library.
             native-lib
             SHARED
             ${SOURCE})

find_library( # Sets the name of the path variable.
              log-lib
              log )
include_directories(${CMAKE_SOURCE_DIR}/include)


set(libs ${CMAKE_SOURCE_DIR}/armeabi-v7a)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${libs}")

target_link_libraries( # Specifies the target library.
                       native-lib

    avfilter avformat  avcodec avutil swresample swscale rtmp z android OpenSLES
                       ${log-lib} )

这里除了ffmpeg相关的库,还引入了libz.so, 这个ffmpeg链接时用到的,否则会报各种错误.

OpenSlES 是用于音频的解码和播放的.

libandroid.so ,这个库用于支持视频播放时的ANativeWindow的相关引用.

五,代码结构

Java层代码比较简单,一个Activity类,主要用来加载一个SurfaceView控件,用来渲染视频,

一个Player.java类,通过native方法,调用ffmpeg的接口,所以有一个同样名字的Player.cpp类,用来跟Player.java对接,会在Native层创建Player.cpp的对象,然后把这个对象的指针传到Java层,这样Java层再去调用Native层方法时,只要把这个指针传过去,就可以在Native层再转回Player.cpp的对象.

extern "C"
JNIEXPORT jlong JNICALL
Java_com_test_ffmpegapplication_EnjoyPlayer_nativeInit(JNIEnv *env, jobject thiz) {
    EnjoyPlayer * enjoyPlayer = new EnjoyPlayer(new JavaCallHelper(javaVm, env, thiz));
    return (jlong) enjoyPlayer;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_test_ffmpegapplication_EnjoyPlayer_setDataSource(JNIEnv *env, jobject thiz,
                                                          jlong native_handler, jstring path_) {
    const char* path = env->GetStringUTFChars(path_,0);
    EnjoyPlayer *enjoyPlayer = reinterpret_cast<EnjoyPlayer *>(native_handler);
    enjoyPlayer->setDataSource(path);

    env->ReleaseStringUTFChars(path_, path);
}

然后是几个基础类:

BaseChannel.h, 对Audio,Video的解码,显示,提取了公共的基类,这里只列出了基本的函数,完整的实现,可以下载附件查看.
class BaseChannel{
virtual void play() =0;

virtual void stop() = 0;

virtual void decode() = 0;

    //这是两个线程安全的队列,
//AVPacket 解码前的数据结构体,从媒体文件读取出的媒体数据,就放入这个队列中,
    SafeQueue<AVPacket *> pkt_queue;
    //AVFrame 解码后的数据结构体,VideoChannel中解码线程会从pkt_queue队列中取出数据,进行解码,
    // 解码后的数据放入frame_queue.后续的播放线程,会从frame_queue队列取出数据,进行渲染。
    SafeQueue<AVFrame *> frame_queue;
}
JavaCallHelper.cpp,用于native层回调java层的实现,用于通知java层,播放准备完成,可以play了,及native层出错后的提示回调.
JavaCallHelper::JavaCallHelper(JavaVM *_javaVM, JNIEnv *_env, jobject &_jobj) :
    javaVM(_javaVM), env(_env){
    //把_jobj创建成一个全局的引用,这里_jobj就是java层的EnjoyPlayer对象。
    jobj = env->NewGlobalRef(_jobj);
    //获取它的class对象,类似反射。
    jclass jclazz = env->GetObjectClass(jobj);

    jmid_error = env->GetMethodID(jclazz, "onError", "(I)V");
    jmid_prepare = env->GetMethodID(jclazz, "onPrepare", "()V");
    jmid_progress = env->GetMethodID(jclazz, "onProgress", "(I)V");
}
SafeQueue.h 一个加了锁的队列,用来存放解码前的AVPackt,和解码后的AVFrame,        
在队列执行出队操作时,多加了一个标记 ,避免死锁.
//当队列是空的时候,会阻塞这里,如果这时调用了stop,因为不会再enqueue,就会一直wait在这里,
        //所以加了mEnable标记,在stop时,mEnable=false,唤醒等待,退出线程,
template<typename T>
class SafeQueue{

    int deQueue(T &value) {
        int ret = 0;
        pthread_mutex_lock(&mutex);
        //当队列是空的时候,会阻塞这里,如果这时调用了stop,因为不会再enqueue,就会一直wait在这里,
        //所以加了mEnable标记,在stop时,mEnable=false,唤醒等待,退出线程,
        while (mEnable && q.empty()) {
            pthread_cond_wait(&cond, &mutex);
        }
        if (!q.empty()) {
            value = q.front();
            q.pop();
            ret = 1;
        }
        pthread_mutex_unlock(&mutex);
        return ret;
    }
}

这一篇文档,先介绍这么多,从下篇开始,讨论下视频的解码,播放.

附件(源码):https://download.csdn.net/download/lin20044140410/12247488

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
qt ffmpeg是一款基于Qt框架和FFmpeg开发的音视频播放器。Qt是一种跨平台的应用程序开发框架,它提供了丰富的图形界面和多媒体功能的支持,使得开发者可以快速开发出功能强大、界面友好的应用程序。而FFmpeg是一种强大的开源多媒体框架,它可以处理音频和视频文件的编码、解码、转码等操作。 在qt ffmpeg视频播放器中,通过集成Qt框架和FFmpeg库,我们可以实现以下功能:首先,播放各种格式的音频和视频文件,包括常见的MP3、MP4、AVI等格式,同时支持流媒体的播放。其次,提供播放控制功能,如暂停、播放、快进、快退等,使用户可以方便地操作音视频内容。此外,还可以实现音视频文件的截图功能,将当前画面保存为图片文件。 对于开发者而言,使用qt ffmpeg视频播放器可以大大简化开发流程,因为Qt框架提供了丰富的图形界面组件和多媒体处理功能,开发者无需从零开始编写播放器的各种功能,只需进行简单的集成和配置即可。而FFmpeg库提供了强大的音视频处理能力,可以方便地实现各种编码、解码、转码等操作。 对于用户而言,qt ffmpeg视频播放器提供了良好的用户体验。通过友好的界面和丰富的功能,用户可以方便地播放各种格式的音视频文件,同时还可以对音视频内容进行自定义设置和调整。因此,qt ffmpeg视频播放器在知乎等社区中也受到了一些开发者和用户的关注和讨论。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值