文章

音视频面试题集锦第 30 期

持续更新的音视频面试题集锦。

音视频面试题集锦第 30 期

本文转自微信公众号 关键帧Keyframe,推荐您关注来获取音视频、AI 领域的最新技术和产品信息

微信公众号 微信扫码关注我们

您还可以加入知识星球 关键帧的音视频开发圈 来一起交流工作中的技术难题、职场经验

知识星球 微信扫码加入星球

我们在知识星球上创建的音视频技术社群关键帧的音视频开发圈已经运营了一段时间了,在这里大家可以一起交流和分享音视频技术知识和实战方案。我们会不定期整理一些音视频相关的面试题,汇集一份音视频面试题集锦(可进入免费订阅)。也会循序渐进地归纳总结音视频技术知识,绘制一幅音视频知识图谱(可进入免费订阅)

下面是第 30 期面试题精选:

  • 1、为什么自制的动态图片导出到相册无法识别成动态图片?
  • 2、iOS 如何实现音频内录,录制当前所有手机的声音集合?
  • 3、应该选择哪种复杂字体渲染的方案 (非 UIView 的能力)?
  • 4、iOS 如何在不解码的情况下给视频添加 Metadata?

1、为什么自制的动态图片导出到相册无法识别成动态图片?

Live Photo 需要有一个特殊的 Metadata Key [kCGImagePropertyMakerAppleDictionary : [17 : <Identifier>]]

因此需要先将此 Metadata 导入到图片中,然后再导出动态图片,这样图片才会被识别成动态图片。

以下是将此 Metadata 导入到图片的 swift 代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
guard let imageSource = CGImageSourceCreateWithURL(photoURL as CFURL, nil),
let imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, nil),
var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable : Any] else {
    throw LivePhotosAssembleError.addPhotoIdentifierFailed
}
let identifierInfo = ["17" : identifier]
imageProperties[kCGImagePropertyMakerAppleDictionary] = identifierInfo
guard let imageDestination = CGImageDestinationCreateWithURL(destinationURL as CFURL, UTType.jpeg.identifier as CFString, 1, nil) else {
    throw LivePhotosAssembleError.createDestinationImageFailed
}
CGImageDestinationAddImage(imageDestination, imageRef, imageProperties as CFDictionary)
if CGImageDestinationFinalize(imageDestination) {
    return destinationURL
} else {
    throw LivePhotosAssembleError.createDestinationImageFailed
}

2、iOS 如何实现音频内录,录制当前所有手机的声音集合?

在 iOS 11 中,ReplayKit 提供了强大的能力:将系统作为一个整体进行直播。用户在控制中心内开启屏幕录制后,ReplayKit2 Extension 可以获取到整个系统级的屏幕画面、以及设备所产生的所有音频,实现跨应用录屏(iOS System Boardcast),同时 ReplayKit 也提供了麦克风采集,这种系统级的直播在应用间切换时也不会停止。可以看下图了解 ReplayKit 的流程。:

ReplayKit 数据流

用户通过手动点击录制按钮然后选择你的应用,则你的 Extension 即可接收到音视频数据,此时你可以在 Extension 里面做一些简单处理或者上传。

更多的内容可以参考:iOS ReplayKit 与 屏幕录制

3、应该选择哪种复杂字体渲染的方案 (非 UIView 的能力)?

看过多个字体渲染的三方库发现有部分平台上还是使用了系统的能力。因为系统的字体渲染更稳定,性能更高,支持的功能也足够丰富。例如 iOS 使用了 CoreText,高性能,支持高级文本布局和多种字体,并且可以轻松的输出图片。

以下是 CoreText 实现文字渲染然后输出到图片的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
CTFontRef font = CTFontCreateWithName(CFSTR("Helvetica-Bold"), 16, NULL);
NSDictionary *attributes = @{(id)kCTFontAttributeName: (__bridge id)font};
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"Hello, World!" attributes:attributes];

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, 280, 50)); // 定义绘制区域
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);

CGContextRef context = UIGraphicsGetCurrentContext(); // 获取当前图形上下文
int width = 280;
int height = 50;
GLubyte *imageData = (GLubyte *) calloc(1, (int)width * (int)height * 4);
if (!context){
    context = CGBitmapContextCreate(imageData, (size_t)width, (size_t)height, 8, (size_t)width * 4, CGColorSpaceCreateDeviceRGB(),  kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
}
CGContextSetGrayFillColor(context, 1.0f, 1.0f);
CGContextSetTextMatrix(context, CGAffineTransformIdentity); // 设置文本矩阵
UIGraphicsPushContext(context);
[attributedString drawAtPoint:CGPointMake(0 , 0)];
CGImageRef a = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:a]; // 输出结果

CGContextRelease(context);
CFRelease(frame);
CGPathRelease(path);
CFRelease(fontName);
CFRelease(font);

4、iOS 如何在不解码的情况下给视频添加 Metadata?

  • 1、初始化 AVAssetReader,创建对应的 AVAssetReaderTrackOutput,包括 videoReaderOutput、audioReaderOutput。注意 videoReaderOutput 吐出的数据应该是 h264/h265 非解码的数据,audioReaderOutput 也应该是 aac 等非解码格式。
  • 2、初始化 AVAssetWriter,创建及对应的 AVAssetWriterInput,包括 videoWriterInput、audioWriterInput。
  • 3、初始化要添加的 AVMetaDataItem。
  • 4、AVAssetWriter 添加来自 AVAssetWriterInputMetadataAdaptor 的 assetWriterInput。
  • 5、AVAssetWriter 进入写状态。
  • 5、使用 AVAssetReader 和 AVAssetWriterInputMetadataAdaptor 写入准备好的 Metadata。
  • 6、videoReaderOutput、audioReaderOutput、videoWriterInput、audioWriterInput 进入读写写状态。
  • 8、读取完所有数据后,让 AVAssetReader 停止读取。使所有 AVAssetWriterInput 标记完成。
  • 9、等待 AVAssetWriter 变为完成状态,视频创建完成。

更多的音视频知识、面试题、技术方案干货可以进群来看:

限时优惠,扫码加入

本文由作者按照 CC BY-NC-ND 4.0 进行授权