开发播放器知识点滴

2020-04-02 18:22:04 浏览数 (1)

前言

这几天重新看了一下播放器的源码,对里边的一些知识又有了一些重新的认识。由于都是一些琐碎的知识点,不好放在其它的文章里,所以只能写这样一篇文章将它们记录下来。

播放器播放字幕原理

  • 字幕分为外挂字幕,硬字幕和软字幕三种。外挂字幕是以第三方文件的方式提供。如.srt 、.ass类型的字幕。硬字幕是将字与视频溶合到一起。软字幕是与媒体格式有关的。它与音频,视频并列,可以作为一个单独的轨进行处理。
  • 播放器显示字幕的大体流程。先将文本通过 FreeType 转成 BitMap, 然后再通过时间戳将这些 BitMap与视频同步后一同渲染出来。(针对的是软字幕与外挂字幕,因为硬字幕是与视频溶和到一起的,所以不用单独处理)

图像缩放

平常的时候我们很少使用图像缩放。但对于播放器来说,在窗口指定的情况下,很可能与最终要显示的YUV的宽高不一致。为了达到更好的效果,一般都需要对视频进行缩放操作。下面就是使用 ffmpeg进行缩放的方法。

注:ffmpeg的 swscale 模块的效率不高,建议尽量使用libyuv进行图像的缩放。

  • 创建上下文
代码语言:javascript复制
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 可以选用下面的参数:

  • 第二步缩放
代码语言:javascript复制
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

his function to update a rectangle within a planar YV12 or IYUV texture with new pixel data.

代码语言:javascript复制
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

this function to lock a portion of the texture for write-only pixel access.

代码语言:javascript复制
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格式。这就要用到音频的数据转换了。

  • 创建上下文
代码语言:javascript复制
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);
  • 初始化上下文
代码语言:javascript复制
int  swr_init (struct SwrContext *s)
  • 重采样
代码语言:javascript复制
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);

小结

知识是不断积累的。在工作和学习的过程中,不断的完善自己的识识图谱,并分享给大家既可以使自己记得更牢固,又可以与大家交流,想来也是一件很美的事儿。

0 人点赞