libVLC 轨道信息
对于媒体文件来说,除了元数据之外,轨道信息也非常有用,例如:编解码器、分辨率、帧率等。由于 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(0, nullptr);
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_parse( libvlc_media_t *p_md );
取而代之的是 libvlc_media_parse_with_options(),所以应尽量使用这个接口,并监听 libvlc_MediaParsedChanged 事件,具体用法可参考《libVLC 事件机制》。
·END·