开源视频播放器IjkPlayer使用记录之(四)--多音轨的探路之旅

2023-05-16

前言:

在视频播放中,我们经常会遇到多音轨的资源文件,比如某个mkv文件同时支持英语/国语,那么最好是能够进行音轨的切换。在IjkPlayer中并没有支持多音轨的代码,所以在移植的过程中,需要自己编写代码,获取多音轨的相关数据。
先感谢一下https://github.com/Bilibili/ijkplayer/issues/72,本文中的代码基本都是copy的Peterede commented on 7 May 2015的回答。

Ijkplayer的代码结构简介及多音轨的实现:

IjkPlayer是基于ffmpeg实现的,如果希望修改ijkplayer获取ffmpeg的内容,那么必须了解Ijkplayer获取ffmpeg数据的大概流程。
下面分层介绍Ijkplayer的主要代码结构

Ijkplayer的java层:IjkMediaPlayer.java

代码主要就是Ijkplayer java的所有接口实现,通过接口访问ndk  c的内容。在本例中,需要添加查询音轨数目,设置当前音轨,查询当前音轨内容这三个接口。这块只是接口封装,没有具体内容,就不详细介绍了。

Ijkplayer的jni层:Ijkplayer_jni.c

好了,从这里开始所有的代码都是c代码了。
static JNINativeMethod g_methods[] = {
        {
                "_setDataSource",
                                       "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
                                                                                                 (void *) IjkMediaPlayer_setDataSourceAndHeaders
        },
在 g_methods中添加对应的方法,如添加获取音轨数目的接口:
 {       "_getAudioTrack",      "()I",                                                    (void *) IjkMediaPlayer_getAudioTrack},

这一层的实现代码如下:

static int IjkMediaPlayer_getAudioTrack(JNIEnv *env, jobject thiz) {
    MPTRACE("%s\n", __func__);
    jint ret = 0;
    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
    JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: start: null mp", LABEL_RETURN);
    ret = ijkmp_get_audio_track(mp);

    LABEL_RETURN:
    ijkmp_dec_ref_p(&mp);
    return ret;
}
获取当前的mediaplayer对象,然后调用Ijkplayer实现层的接口去获取内容。


Ijkplayer的实现层:ijkplayer.c

这里需要补充说明一下,ijkplayer是基于ffmpeg的,播放器是基于ffplay的,所以在ijkplayer初始化的时候会获取1个ffplay的实例。具体代码如下:
  IjkMediaPlayer *mp = (IjkMediaPlayer *) mallocz(sizeof(IjkMediaPlayer));
    if (!mp)
        goto fail;

    mp->ffplayer = ffp_create();
其实我们获取音轨之类的内容都是在这个实例上获取的。这一层主要就是把相关的信息透传给ff_player来处理。
这里获取音轨数目的代码如下:
int ijkmp_get_audio_track(IjkMediaPlayer *mp)
{
    assert(mp);
    pthread_mutex_lock(&mp->mutex);
    int ret=ffp_get_audio_track_info_l(mp->ffplayer);
    pthread_mutex_unlock(&mp->mutex);
    return ret;
}

ffplay的实现:ffplay.c

在这一层来实现具体的代码。
代码请参见https://github.com/Bilibili/ijkplayer/issues/72。
这样,我们已经可以获取到这个视频有几个音轨,并可以对其进行设置了。
但是,这样有个问题了,音轨知道有几个,怎么区分呢?

多音轨信息的获取

基于mpeg,mpeg提供ffprobe读取视频的资源内容:
具体信息可以见下:
ffprobe -i test.mkv
ffprobe version N-82166-g894e7ef Copyright (c) 2007-2016 the FFmpeg developers
  built with Apple LLVM version 8.0.0 (clang-800.0.38)
  configuration: --disable-yasm
  libavutil      55. 35.100 / 55. 35.100
  libavcodec     57. 65.100 / 57. 65.100
  libavformat    57. 57.100 / 57. 57.100
  libavdevice    57.  2.100 / 57.  2.100
  libavfilter     6. 66.100 /  6. 66.100
  libswscale      4.  3.100 /  4.  3.100
  libswresample   2.  4.100 /  2.  4.100
Input #0, matroska,webm, from 'test.mkv':
  Metadata:
    encoder         : libebml v1.3.1 + libmatroska v1.4.2
    creation_time   : 2016-09-14T13:42:18.000000Z
  Duration: 01:50:20.39, start: 0.000000, bitrate: 3223 kb/s
    Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x816, SAR 1:1 DAR 40:17, 24.04 fps, 24.04 tbr, 1k tbn, 48 tbc (default)
    Metadata:
      BPS             : 2965476
      BPS-eng         : 2965476
      DURATION        : 01:50:20.054000000
      DURATION-eng    : 01:50:20.054000000
      NUMBER_OF_FRAMES: 158242
      NUMBER_OF_FRAMES-eng: 158242
      NUMBER_OF_BYTES : 2453951583
      NUMBER_OF_BYTES-eng: 2453951583
      _STATISTICS_WRITING_APP: mkvmerge v8.3.0 ('Over the Horizon') 64bit
      _STATISTICS_WRITING_APP-eng: mkvmerge v8.3.0 ('Over the Horizon') 64bit
      _STATISTICS_WRITING_DATE_UTC: 2016-09-14 13:42:18
      _STATISTICS_WRITING_DATE_UTC-eng: 2016-09-14 13:42:18
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
    Stream #0:1(chi): Audio: aac (LC), 44100 Hz, stereo, fltp (default)
    Metadata:
      title           : 粤语
      BPS             : 127484
      BPS-eng         : 127484
      DURATION        : 01:50:20.268000000
      DURATION-eng    : 01:50:20.268000000
      NUMBER_OF_FRAMES: 283964
      NUMBER_OF_FRAMES-eng: 283964
      NUMBER_OF_BYTES : 105498100
      NUMBER_OF_BYTES-eng: 105498100
      _STATISTICS_WRITING_APP: mkvmerge v8.3.0 ('Over the Horizon') 64bit
      _STATISTICS_WRITING_APP-eng: mkvmerge v8.3.0 ('Over the Horizon') 64bit
      _STATISTICS_WRITING_DATE_UTC: 2016-09-14 13:42:18
      _STATISTICS_WRITING_DATE_UTC-eng: 2016-09-14 13:42:18
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
    Stream #0:2(chi): Audio: aac (LC), 44100 Hz, stereo, fltp
    Metadata:
      title           : 国语
      BPS             : 127482
      BPS-eng         : 127482
      DURATION        : 01:50:20.390000000
      DURATION-eng    : 01:50:20.390000000
      NUMBER_OF_FRAMES: 283964
      NUMBER_OF_FRAMES-eng: 283964
      NUMBER_OF_BYTES : 105498100
      NUMBER_OF_BYTES-eng: 105498100
      _STATISTICS_WRITING_APP: mkvmerge v8.3.0 ('Over the Horizon') 64bit
      _STATISTICS_WRITING_APP-eng: mkvmerge v8.3.0 ('Over the Horizon') 64bit
      _STATISTICS_WRITING_DATE_UTC: 2016-09-14 13:42:18
      _STATISTICS_WRITING_DATE_UTC-eng: 2016-09-14 13:42:18
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

ffmpeg的下载和编译这里就不说了,可以自行baidu。可以看到title可以清楚的区分出audio stream.
如果对前面代码有研究过,那么应该知道每个stream对应的是一个AVStream,AVStream中有 AVDictionary *metadata;
   这个字段对应的就是上面的MetaData。获取内容的代码参考了IjkPlayer获取MetaData的代码结构。
   构建了一个新的IjkStreamMediaMeta,结构源自:IjkMediaMeta。
   附一下我的代码中主要函数:
IjkStreamMediaMeta *ffp_get_audio_meta_l(FFPlayer *ffp,int index)
{
    if (!ffp)
        return NULL;
    assert(ffp);
    VideoState *is = ffp->is;
    int total = 0;
    if (!is)
        return EIJK_NULL_IS_PTR;

    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
    AVStream *st;
    int codec_type = AVMEDIA_TYPE_AUDIO;

    if (codec_type == AVMEDIA_TYPE_VIDEO)
        start_index = is->video_stream;
    else if (codec_type == AVMEDIA_TYPE_AUDIO)
        start_index = is->audio_stream;
/*else
    start_index = is->subtitle_stream;
if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
    return;*/

    for (stream_index = 0; stream_index < is->ic->nb_streams; stream_index++)
    {
        st = ic->streams[stream_index];
        if (st->codec->codec_type == codec_type) {
            /* check that parameters are OK */
            switch(codec_type) {
                case AVMEDIA_TYPE_AUDIO:
                    if (st->codec->sample_rate != 0 &&
                        st->codec->channels != 0)
                        total++;
                    if (total == index)
                        goto the_end;
                    break;

            }
        }
    }
    return NULL;
    the_end:
        return ijkstreammeta_get_streammeta_l(st->metadata);
}
IjkStreamMediaMeta *ijkstreammeta_get_streammeta_l(AVDictionary *meta)
{
    if (!meta)
        return NULL;
    IjkStreamMediaMeta *stream_meta = NULL;
    stream_meta = ijkstreammeta_create();
    if (!stream_meta) {
        ijkstreammeta_destroy_p(&stream_meta);
        return NULL;
    }
    AVDictionaryEntry *entry=av_dict_get(meta,"title",NULL,0);
    char *title="";
    if (!entry  || !entry->value)
    {
        title="";
    }
    else
    {
        title=entry->value;
    }
    ijkstreammeta_set_string_l(stream_meta, IJKSTREAMM_KEY_FORMAT, title);
    return stream_meta;
}

以上就是基于Ijkplayer的多音轨实现。
   

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

开源视频播放器IjkPlayer使用记录之(四)--多音轨的探路之旅 的相关文章

  • 游戏客户端编程

    游戏客户端编程 1 代码实现服务器连接发送按钮 2 显示消息3 发送信息4 播放背景音乐5 变换游戏背景图片6 参考 1 代码实现 服务器连接 span class token keyword private span span class
  • 卷积神经网络实现表情识别

    卷积神经网络实现表情识别 CNN人脸表情识别图片预处理原本效果处理后效果 图片数据集效果 CNN人脸识别创建模型归一化与数据增强创建网络 摄像头人脸识别图片识别 参考 CNN人脸表情识别 图片预处理 span class token key
  • IIC协议及其工程【FPGA】

    IIC协议及其工程 FPGA 一 IIC协议1 IIC简介2 IIC中相关的术语1 应答信号 xff08 ACK xff09 2 无应答信号 xff08 NOACK xff09 3 虚写3 IIC的时序 二 EEPROM1 时钟频率2 起始
  • char *与char []的区别

    其实 xff0c 只要记住一点就能很好区分char 和char xff1a char 定义的是一个指向字符串的指针 xff08 注意 xff1a C语言中没有对应字符串的内置类型或者类类型 xff09 xff0c 而char 就是C语言中的
  • SPI协议读取FLASH【FPGA】

    SPI协议读取FLASH FPGA 一 SPI协议1 SPI简介2 SPI物理层3 SPI协议层CPOL CPHA 及通讯模式 4 SPI 基本通讯过程5 通讯的起始和停止信号6 数据有效性 二 Flash1 状态寄存器1 WIP xff0
  • 基于FPGA的图像边缘检测

    基于FPGA的图像边缘检测 一 图像处理算法1 灰度转换2 高斯滤波3 二值化4 Sobel 二 项目框架1 摄像头配置模块2 图像处理模块3 数据缓存模块4 其它模块 三 部分代码1 数据采集模块2 读写控制模块 四 参考五 源码 简介
  • 基本认证_摘要认证_HTTPS

    1 HTTP基本认证 HTTP提供了一个原生的质询 响应 xff08 challenge response xff09 框架 Web应用程序收到一条HTTP请求报文时 xff0c 服务器没有按照请求执行动作 xff0c 而是以一个 认证质询
  • 什么是奇校验(Odd Parity),什么是偶校验(Even Parity)?

  • 2021-03-08

    今天在网上安装PR xff0c 网上下载的安装器把电脑默认装了一大堆垃圾工具 xff0c 依次删除后突然发现谷歌浏览器主页被篡改了 xff0c 随后用360等工具修复 xff0c 均提示无异常 通过浏览器设置和重置主页后仍然无效 xff0c
  • 2021-03-08

    大疆无人机自己动手更换电芯的注意事项 xff0c 当电池多电芯出现均大压差且调整数据无效后 xff0c 或发现某块或多块电芯鼓包 xff0c 说明电芯已经老化 xff0c 寿命用尽 xff0c 就需要更换电芯了 xff0c 厂家为保护消费者
  • can't run '/etc/init.d/rcS': No such file or directory 最终解决方法

    drivers rtc hctosys c unable to open rtc device rtc0 end request I O error dev mtdblock2 sector 256 isofs fill super bre
  • Ubuntu下的CuteCom串口详细调试教程

    I MX6ULL嵌入式开发学习 串口调试 一 Ubuntu下的串口调试助手安装 嵌入式开发学习过程中学习到串口调试这一章 xff0c 以前在Win10操作时都有相对应的串口调试界面 xff0c 安装个串口驱动在电脑设备端口里面看到COM3时
  • STM32 串口

    文章目录 USART 通信协议RS 232与TTL电平 串口通信数据包组成USART功能框图讲解引脚寄存器状态寄存器 USART SR 数据寄存器 USART DR 控制寄存器 USART CR 波特比率寄存器 USART BRR 发送过程
  • printf二进制数据

    基于之前这篇文章的代码改进了下 xff1a http blog csdn net xzongyuan article details 28889063 之前打印的数字没有补0 我打印了内存信息 xff0c 结果是这样的 xff0c 不能对齐
  • 分析MySQL数据类型的长度

    分析MySQL数据类型的长度 MySQL有几种数据类型可以限制类型的 34 长度 34 xff0c 有CHAR Length VARCHAR Length TINYINT Length SMALLINT Length MEDIUMINT L
  • 为vscode配置clangd

    目录 安装clangd 后端安装clangd 前端修改基础配置生成compile commands json文件基本效果补全warning提醒自动修改存在问题 注意事项 clangd能提供更好的补全和提示 xff0c 自带检查一些warni
  • 论文笔记(十九)RGB-D Object Tracking: A Particle Filter Approach on GPU

    RGB D Object Tracking A Particle Filter Approach on GPU 文章概括摘要1 介绍2 贡献3 粒子滤波器4 可能性评估5 实施细节6 实验A 物体模型B 合成序列C 真实序列 7 结论8 鸣
  • Ubuntu 命令行 访问网页

    安装w3m 1 进入 root apt get install w3m 2 测试是否成功 xff1a w3m https blog csdn net x xx xxx xxxx article details 92574331
  • 代码管理中Trunk、Branches、Tags的区别和联系

    我们可以将这三者想象成一棵树的组成部分 trunk为树干branches为树枝tags为整棵树 trunk用于主线开发 branches用于定制版本 修复bugs 并行开发等使用 tags用于存放release版本 xff0c 阶段性代码
  • linux使用curl请求(带参数)

    1 2 3 curl G d 34 c 61 amp a 61 34 http www net index php

随机推荐

  • 惯导系列(二):滤波相关的算法

    前言 我又消失了一段时间 xff0c 这段时间研究了惯性导航有关的算法 xff0c 整理了不少博客 xff0c 字数比较多 xff0c 图片比较多 学到了很多知识 目录 前言 本节介绍 一 Mahony算法 1 1 PID控制算法 1 2
  • STM32 CAN 设置多个过滤器接收多ID方法

    1 标识符列表模式 xff0c 32位模式下 void MX CAN Init void 这里是实现了两个地址的接收 一个是用来接收广播信息 一个用来接收私有地址 如果想实现多个地址可以添加多个过滤器组 stm32103 有0 13 共14
  • linux下运行动态库问题 cannot open shared object file: No such file or directory

    如果动态库不在同一级目录下 xff0c 则需要将以上文件的目录加载到动态库搜索路径中 xff0c 设置的方式有以下几种 一 将动态库路径加入到LD LIBRARY PATH环境变量 1 在终端输入 xff1a export LD LIBRA
  • 几个串口通信协议的整理

    一 UART UART是一个大家族 xff0c 其包括了RS232 RS499 RS423 RS422和RS485等接口标准规范和总线标准规范 它们的主要区别在于其各自的电平范围不相同 嵌入式设备中常常使用到的是TTL TTL转RS232的
  • 单片机中断的过程

    1 根据响应的中断源的中断优先级 使相应的优先级状态触发器置1 xff1b 2 把当前程序计数器PC的内容压入堆栈 xff0c 保护断点 xff0c 寻找中断源 xff1b 3 执行硬件中断服务子程序调用 xff1b 4 清除相应的中断请求
  • Ruby学习札记(3)- Ruby中gem的安装与卸载

    Ruby 学习札记 3 Ruby 中 gem 的安装与卸载 在 Ruby 中有 gem 包这种概念 xff0c 类似 PHP 中的 pear xff0c 相当于一种插件 具体可以 Google 一下 xff08 1 xff09 查看已经安装
  • 【linux】ubuntu20.04 运行软件 提示找不到过时的库 libQtCore.so.4、libQtGui.so.4、libpng12.so.0

    先上结果 1 nxView运行起来 环境 硬件 xff1a Jetson Xavier NX 套件 系统 xff1a Ubuntu 20 04 软件 xff1a nxView 43 libQtCore so 4 解决 0 现象 运行软件提示
  • rtt相关问题总结

    1 总结RT Thread的启动流程 xff08 启动文件部分跳过 xff09 关中断 rt hw interrupt disable 板级初始化 xff1a 需在该函数内部进行系统堆的初始化 rt hw board init 打印 RT
  • FTP 客户端C实现

    使用 Socket 通信实现 FTP 客户端程序 FTP 概述 文件传输协议 xff08 FTP xff09 作为网络共享文件的传输协议 xff0c 在网络应用软件中具有广泛的应用 FTP的目标是提高文件的共享性和可靠高效地传送数据 在传输
  • Qt编写串口通信程序全程图文讲解

    说明 我们的编程环境是windows xp下 xff0c 在Qt Creator中进行 xff0c 如果在Linux下或直接用源码编写 xff0c 程序稍有不同 xff0c 请自己改动 在Qt中并没有特定的串口控制类 xff0c 现在大部分
  • VLC播放器调试经验总结

    一 前言 在使用VS学习VLC源码时 xff0c 可以打断点分析变量数据 xff0c 跟踪代码流程 xff0c 方便我们理解源码 但是在定位音视频卡顿 延时等疑难问题时 xff0c 这一招就不管用了 xff0c 因为打上断点就会导致实时计算
  • http协议如何解决粘包问题

    在讲粘包问题之前 xff0c 首先得明白这个包是应用层的数据包 当数据在传输层时 xff0c 由于TCP是面向字节流的 xff0c 所以它看到的数据是按照顺序一个个放在缓冲区中的 xff0c 而对于应用层而言 xff0c 看到的只是一连串的
  • ROS- 解决 sudo rosdep init和update 出现的错误

    大家在使用ROS时都需要执行sudo rosdep init 方法和rosdep update方法 但是在执行rosdep init时会提示如下错误 ERROR cannot download default sources list fr
  • 如何用MQTT网关快速接入阿里云IOT

    深圳市钡铼技术有限公司推出的BL102 xff0c 是采集西门子 xff0c 欧姆龙 xff0c 三菱 xff0c 台达 xff0c AB xff0c 施耐德等主流PLC及Modbus xff0c DT L645协议设备数据 xff0c 简
  • 闫刚 qgc模块mavlinklog实现过程

    mavlink log qml部分 这样logController就和LogDownloadController进行了绑定 AnalyzeView qml Rectangle span class token punctuation spa
  • 初识TVM--TVM的编译与安装

    TVM是什么 xff1f Apache incubating TVM is an open deep learning compiler stack for CPUs GPUs and specialized accelerators It
  • iOS上简单推送通知(Push Notification)的实现

    iOS上简单推送通知 xff08 Push Notification xff09 的实现 根据这篇很好的教程 xff08 http www raywenderlich com 3443 apple push notification ser
  • Android学习记录(十三) http之digest鉴权之填坑6.0。

    背景 xff1a android 6 0 1 的手机发现使用webdav下载文件实效 xff0c httpclient execute get的时候出现 xff1a CrashHandler java lang ArrayIndexOutO
  • 开源视频播放器IjkPlayer使用记录之(三)--播放视频从上次播放的时间点播放。

    方法 xff1a 1 在关闭视频的时候 xff0c 使用getCurrentPosition 获取当前的时间点 2 使用SharedPreferences记录当前的时间点 3 重新播放时 xff0c 获取该时间点 xff0c 使用seekt
  • 开源视频播放器IjkPlayer使用记录之(四)--多音轨的探路之旅

    前言 xff1a 在视频播放中 xff0c 我们经常会遇到多音轨的资源文件 xff0c 比如某个mkv文件同时支持英语 国语 xff0c 那么最好是能够进行音轨的切换 在IjkPlayer中并没有支持多音轨的代码 xff0c 所以在移植的过