前言
这几天重新看了一下播放器的源码,对里边的一些知识又有了一些重新的认识。由于都是一些琐碎的知识点,不好放在其它的文章里,所以只能写这样一篇文章将它们记录下来。
播放器播放字幕原理
- 字幕分为外挂字幕,硬字幕和软字幕三种。外挂字幕是以第三方文件的方式提供。如.srt 、.ass类型的字幕。硬字幕是将字与视频溶合到一起。软字幕是与媒体格式有关的。它与音频,视频并列,可以作为一个单独的轨进行处理。
- 播放器显示字幕的大体流程。先将文本通过 FreeType 转成 BitMap, 然后再通过时间戳将这些 BitMap与视频同步后一同渲染出来。(针对的是软字幕与外挂字幕,因为硬字幕是与视频溶和到一起的,所以不用单独处理)
图像缩放
平常的时候我们很少使用图像缩放。但对于播放器来说,在窗口指定的情况下,很可能与最终要显示的YUV的宽高不一致。为了达到更好的效果,一般都需要对视频进行缩放操作。下面就是使用 ffmpeg进行缩放的方法。
注:ffmpeg的 swscale 模块的效率不高,建议尽量使用libyuv进行图像的缩放。
- 创建上下文
sws_getCachedContext(*img_convert_ctx,
frame->width, frame->height, frame->format, frame->width, frame->height,
AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL);
或
sws_getContext(*img_convert_ctx,
frame->width, frame->height, frame->format, frame->width, frame->height,
AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL);
sws_flags 可以选用下面的参数:
- 第二步缩放
uint8_t *pixels[4];
int pitch[4];
sws_scale(*sws_convert_ctx, (const uint8_t * const *)frame->data,
frame->linesize, 0, frame->height, pixels, pitch);
- sws_convert_ctx: sws上下文.
- frame->data: 指向 YUV数据。(pointer to the picture/channel planes)
- frame->linesize: 指明YUV数据每行的宽度。
- pixels: 输入数据地址
- pitch: 输入YUV/RGBA数据每行的宽度。
SDL 个别 API 讲解
下面几个 SDL 的API之前没有用过,但今天看代码时发现这几个API非常有用,所以在这里记录一下,以便后面使用时便于查阅。
SDL_UpdateYUVTexture
代码语言:javascript复制his function to update a rectangle within a planar YV12 or IYUV texture with new pixel data.
int SDL_UpdateYUVTexture(SDL_Texture* texture,
const SDL_Rect* rect,
const Uint8* Yplane, //Y分量
int Ypitch, //Y分量每行宽度
const Uint8* Uplane, //U分量
int Upitch, //U分量每行宽度
const Uint8* Vplane, //V分量
int Vpitch //V分量每行宽度
)
例子:
代码语言:javascript复制ret = SDL_UpdateYUVTexture(tex, NULL,
frame->data[0], frame->linesize[0],
frame->data[1], frame->linesize[1],
frame->data[2], frame->linesize[2]);
SDL_LockTexture
代码语言:javascript复制this function to lock a portion of the texture for write-only pixel access.
int SDL_LockTexture(SDL_Texture* texture,
const SDL_Rect* rect,
void** pixels,
int* pitch)
例子
代码语言:javascript复制uint8_t *pixels[4];
int pitch[4];
SDL_LockTexture(tex, NULL, (void **)pixels, pitch);
SDL_UnlockTexture
this function to unlock a texture, uploading the changes to video memory
音频重采样
在一些媒体文件中使用的音频数据格式是 FLTP格式,也就是 float格式。之前没有仔细研究过,以为都是用16位大小,这两天才搞明白原来是32位大小。
而使用SDL将音频在送往硬件设备时,一般都使用的是 16位大小的数据。这样数据不一致就导致音频在播放时出现了问题。所以最好的解决办法是将 FLTP 格式转换成 S16格式。这就要用到音频的数据转换了。
- 创建上下文
struct SwrContext swr_alloc_set_opts(struct SwrContext *s,
int64_t out_ch_layout,
enum AVSampleFormat out_sample_fmt,
int out_sample_rate,
int64_t in_ch_layout,
enum AVSampleFormat in_sample_fmt,
int in_sample_rate,
int log_offset,
void *log_ctx) ;
例子
代码语言:javascript复制swr_alloc_set_opts(NULL,
is->audio_tgt.channel_layout,
is->audio_tgt.fmt, is->audio_tgt.freq,
dec_channel_layout,
af->frame->format,
af->frame->sample_rate,
0, NULL);
- 初始化上下文
int swr_init (struct SwrContext *s)
- 重采样
int swr_convert (struct SwrContext *s,
uint8_t *out_arg[SWR_CH_MAX],
int out_count,
const uint8_t *in_arg[SWR_CH_MAX],
int in_count) ;
例子
代码语言:javascript复制int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate 256;
swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);
小结
知识是不断积累的。在工作和学习的过程中,不断的完善自己的识识图谱,并分享给大家既可以使自己记得更牢固,又可以与大家交流,想来也是一件很美的事儿。