libVLC 轨道信息

高效程序员

共 2003字,需浏览 5分钟

 ·

2020-09-05 14:52

对于媒体文件来说,除了元数据之外,轨道信息也非常有用,例如:编解码器、分辨率、帧率等。由于 VLC media player 能够显示这些信息,所以 libVLC 也可以做到这一点。


像常见的视频文件(例如:电影),我们看到的是一个整体,但实际上一般会被分为音频和视频两部分。如果将电影导入视频编辑软件,可以很容易地看到音频和视频是分开的 - 视频在视频轨道上,音频在音频轨道上。如果有需求,甚至还可以对它们进行编辑(音量、声道、时间、制式等)。



1

轨道信息


要解析 libVLC 中的媒体信息,有必要先了解一下它里面的一些数据结构。



媒体轨道信息


媒体轨道信息由 libvlc_media_track_t 表示:


typedef struct libvlc_media_track_t
{

    /* Codec fourcc */
    uint32_t    i_codec;  // 编解码器
    uint32_t    i_original_fourcc;  // 四字符代码
    int         i_id;  // 轨道 ID
    libvlc_track_type_t i_type;   // 类型

    /* Codec specific */
    int         i_profile;  // 编码级别
    int         i_level;  // 级别的等级

    union {
        libvlc_audio_track_t *audio;  // 音频轨道
        libvlc_video_track_t *video;  // 视频轨道
        libvlc_subtitle_track_t *subtitle;  // 字幕轨道
    };

    unsigned int i_bitrate;  // 码率
    char *psz_language;  // 语言
    char *psz_description;  // 描述

libvlc_media_track_t;


i_codec 和 i_original_fourcc 的类型是 uint32_t,并不具有可读性。若想获取一个可读信息,需要使用 libvlc_media_get_codec_description() 进行转换。



轨道类型


轨道类型由 libvlc_track_type_t 表示:


typedef enum libvlc_track_type_t
{
    libvlc_track_unknown   = -1,  // 未知
    libvlc_track_audio     = 0,   // 音频
    libvlc_track_video     = 1,   // 视频
    libvlc_track_text      = 2    // 文字
libvlc_track_type_t;


有了这些值,可以很容易的根据 i_type 来判断轨道类型。



音频轨道


音频轨道由 libvlc_audio_track_t 表示:


typedef struct libvlc_audio_track_t
{

    unsigned    i_channels;  // 声道
    unsigned    i_rate;      // 采样率
libvlc_audio_track_t;



视频轨道


视频轨道由 libvlc_video_track_t 表示:


typedef struct libvlc_video_track_t
{

    unsigned    i_height;          // 视频高度
    unsigned    i_width;           // 视频宽度
    unsigned    i_sar_num;         // 像素宽高比的分子   
    unsigned    i_sar_den;         // 像素宽高比的分母
    unsigned    i_frame_rate_num;  // 帧率的分子
    unsigned    i_frame_rate_den;  // 帧率的分母

    libvlc_video_orient_t       i_orientation;  // 方向
    libvlc_video_projection_t   i_projection;
    libvlc_video_viewpoint_t    pose; /**< Initial view point */
libvlc_video_track_t;


有两个字母需要解释一下:num 是 numerator 的缩写,表示分子;den 是 denominator 的缩写,表示分母。


倘若要计算帧率(FPS,每秒钟多少帧画面),可以通过 i_frame_rate_num/i_frame_rate_den 来获得。



字幕轨道


字幕轨道由 libvlc_subtitle_track_t 表示:


typedef struct libvlc_subtitle_track_t
{

    char *psz_encoding;  // 编码
libvlc_subtitle_track_t;



2

获取轨道信息


以本地的一个视频文件为例,来看看它的轨道信息:



需要注意的是,在获取轨道信息之前,需要先调用解析媒体文件(例如:使用 libvlc_media_parse() ),或者至少播放一次多媒体:


int main()
{
    const char * localMrl = "Sample.mkv";

    libvlc_instance_t *instance;
    libvlc_media_t *media;

    instance = libvlc_new(0nullptr);
    media = libvlc_media_new_path(instance, localMrl);

    // 解析媒体以从中读取信息
    libvlc_media_parse(media);

    // 获取轨道信息
    reading(media);

    libvlc_media_release(media);
    libvlc_release(instance);

    getchar();

    return 0;
}


具体的获取如下,主要利用 libvlc_media_tracks_get() 接口:


// 获取轨道信息
void reading(libvlc_media_t *media)
{
    // 用于存储媒体轨迹的信息
    libvlc_media_track_t **tracks;
    unsigned tracksCount;

    // 获取轨道信息
    tracksCount = libvlc_media_tracks_get(media, &tracks);
    if (tracksCount <= 0)
        return;

    for (unsigned i = 0; i < tracksCount; i++) {
        libvlc_media_track_t *track = tracks[i];

        cout << "i_type: " << track->i_type << endl;
        cout << "i_codec: " << track->i_codec << endl;
        cout << "i_original_fourcc: " << track->i_original_fourcc << endl;

        // 编解码器
        const char* codec = libvlc_media_get_codec_description(track->i_type, track->i_codec);
        const char* fourcc_codec = libvlc_media_get_codec_description(track->i_type, track->i_original_fourcc);

        if (nullptr != codec)
            cout << "track codec: " << codec << endl;

        if (nullptr !=  fourcc_codec)
            cout << "fourcc codec: " << fourcc_codec << endl;

        cout << "i_profile: " << track->i_profile << endl;
        cout << "i_level: " << track->i_level << endl;

        if (nullptr != track->psz_language)
            cout << "psz_language: " << track->psz_language << endl;

        if (nullptr != track->psz_description)
            cout << "psz_description: " << track->psz_description << endl;

        // 音频轨道
        if (track->i_type == libvlc_track_audio) {
            libvlc_audio_track_t *audioTrack = track->audio;
            cout << "i_channels: " << audioTrack->i_channels << endl;
            cout << "i_rate: " << audioTrack->i_rate << endl;
        } else if (track->i_type == libvlc_track_video) {  // 视频轨道
            libvlc_video_track_t *videoTrack = track->video;

            // 视频宽度、高度
            cout << "i_width: " << videoTrack->i_width << endl;
            cout << "i_height: " << videoTrack->i_height << endl;
            cout << "i_sar_num: " << videoTrack->i_sar_num << endl;
            cout << "i_sar_den: " << videoTrack->i_sar_den << endl;
            cout << "i_frame_rate_num: " << videoTrack->i_frame_rate_num << endl;
            cout << "i_frame_rate_den: " << videoTrack->i_frame_rate_den << endl;

            // 帧率
            if (videoTrack->i_sar_num > 0) {
                double frameRate = videoTrack->i_frame_rate_num / double(videoTrack->i_frame_rate_den);
                cout << "frame_rate: " << frameRate << endl;
            }

            // 像素宽高比
            if (videoTrack->i_sar_num > 0) {
                double sar = videoTrack->i_sar_num / double(videoTrack->i_sar_den);
                cout << "sar: " << sar << endl;
            }
        }
        cout << "--------------------" << endl;
    }

    libvlc_media_tracks_release(tracks, tracksCount);
}



3

还有些什么


其实上面偷了个懒,因为 libvlc_media_parse() 这个接口已经被遗弃了,并不推荐使用:


LIBVLC_DEPRECATED LIBVLC_API void
libvlc_media_parselibvlc_media_t *p_md )
;


取而代之的是 libvlc_media_parse_with_options(),所以应尽量使用这个接口,并监听 libvlc_MediaParsedChanged 事件,具体用法可参考《libVLC 事件机制》。


·END·
 

作者:一去、二三里
爱学习,爱编程,爱生活。
欢迎来撩,一起畅谈程序人生!

点个在看,么么哒!

浏览 99
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报